我解决了一个模拟制造单元产品的并发问题。我使用 13 个未命名的信号量,它们由运行问题的“部分”的 8 个线程处理。
执行周期测量“t1”在之后执行phtread_create
,“t2”在之后执行pthread_join
,从而获得 pthreads 的工作时间(这是我感兴趣的值)。t2 -t1 的减法给出了结束线程的执行时间。
我注意到获得的值范围太广了,我已经测量了接近 30,000 个周期的值。以及1.46亿次循环的价值。
为了测量 cicles,我使用了一个驱动程序“cicle_count”,它读取双核处理器 ARM Cortex A9 的注册表值 R15,该寄存器计算执行的指令数。我使用的嵌入式系统是“ZedBoard”:
http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,400.1028&Prod=ZEDBOARD
我用 2 线程问题进行了测量,更简单并且在每次测量之间得到相似的值。
我究竟做错了什么?可以更改程序每次运行之间执行时间的测量吗?
编辑 2:编码双核和单核测量。
对于双核执行(run./Apliacion.out):
我创建了两个相同的驱动程序(编写相同的代码,除了设备名称“DEVICE_NAME”),但一个称为“contador_ciclos1”,另一个称为“contador_ciclos2”(两个驱动程序相同可以吗??)
这些驱动程序在每个内核上插入一个脚本:
insmod hpn_driver.ko
-> Taskset 1 insmod contador_ciclos1.ko
-> Taskset 2 insmod contador_ciclos2.ko
mknod / dev / hpn_driver c 251 0
-> Mknod / dev/contador_ciclos1 c 250 0
-> Mknod / dev/contador_ciclos2 c 249 0
然后,在应用程序中,我使用两个文件描述符打开两个驱动程序,并使用 t2-t1 (core1) 和 t4-t3 (core2) 进行相关测量。
要执行单核,请插入两个驱动程序,但只打开一个驱动程序并运行任务集 1 以测量驱动程序“contador_ciclos1”上的时钟周期。并检查 t2-t1 cicles。
这是应用程序的伪代码:
int i = 0;
char buff[24];
volatile unsigned int tiempo1, tiempo2;
tiempo1 = 0;
tiempo2 = 0;
volatile unsigned int overhead = 0;
int fd1, fd2 = 0;
fd1 = open("/dev/contador_ciclos1", O_RDWR | O_NOCTTY | O_NONBLOCK);
fd2 = open("/dev/contador_ciclos2", O_RDWR | O_NOCTTY | O_NONBLOCK);
iret1 = pthread_create( &thread1, NULL , hilo1_funcion, (void*) mensaje1);
if (iret1!=0){
printf("Fallo en creacion hilo 1 %d\n", iret1);
}
//create 8 Pthreads...
//measurement "t1" from core 1 and "t3" from core 2:
for(i=0;i<10;i++){
read (fd1,buff,11);
sscanf(buff,"%u",&tiempo1);
}
for(i=0;i<10;i++){
read (fd2,buff,11);
sscanf(buff,"%u",&tiempo3);
}
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
//measurement "t2" from core 1 and t4 from core 2:
read (fd1,buff,11);
sscanf(buff,"%u",&tiempo2);
read (fd2,buff,11);
sscanf(buff,"%u",&tiempo4);
printf(COLOR_VERDE"Ciclos_ejecucion_core1: %u"COLOR_RESET "\n", (tiempo2 - tiempo1));
printf(COLOR_VERDE"Ciclos_ejecucion_core2: %u"COLOR_RESET "\n", (tiempo4 - tiempo3));
这是使用信号量的“phtread 1”的代码......
void *hilo1_funcion( void *ptr ){
//~ printf(COLOR_MAGENTA"HILO 1"COLOR_RESET"\n");
int fabricados3=0;
int rc=0;
/* Mientras que no se hayan finalizado de fabricar todos los productos 3,
* el robot 1 funciona */
while (fabricados3<productos3){
rc = sem_trywait(&P3M3);
if (rc==-1 && errno == EAGAIN) { /* no teller available */
//~ printf("ROBOT 1 semaforo P3M3 ocupado"COLOR_RESET"\n");
}
if (rc==0){
fabricados3++;
//~ printf(COLOR_CYAN" PRODUCTO TIPO 3 FINALIZADO - Cantidad de productos tipo 3 fabricados: %d"COLOR_RESET"\n", fabricados3);
sem_post(&P3R1);
}
//~ printf("YIELD ROBOT 1\n");
pthread_yield();
}
printf(COLOR_ROJO"FIN ROBOT 1"COLOR_RESET"\n");
pthread_exit(NULL);
return NULL;
}
这是驱动程序“contador_ciclos1.ko”的伪代码,与 contador_ciclos2.ko 相同(
static inline void init_perfcounters (int do_reset, int enable_divider)
{
// in general enable all counters (including cycle counter)
static int value = 1;
// peform reset:
if (do_reset)
{
value |= 2; // reset all counters to zero.
value |= 4; // reset cycle counter to zero.
}
if (enable_divider)
value |= 8; // enable "by 64" divider for CCNT.
value |= 16;
// program the performance-counter control-register:
asm volatile ("MCR p15, 0, %0, c9, c12, 0\t\n" :: "r"(value));
// enable all counters:
asm volatile ("MCR p15, 0, %0, c9, c12, 1\t\n" :: "r"(0x8000000f));
// clear overflows:
asm volatile ("MCR p15, 0, %0, c9, c12, 3\t\n" :: "r"(0x8000000f));
}
static inline unsigned int get_cyclecount (void)
{
volatile unsigned int value;
asm volatile ("MRC p15, 0, %0, c9, c13, 0\t\n": "=r"(value));
return value;
}
int init_module(void)
{
init_perfcounters(1,0);
Major = register_chrdev(0, DEVICE_NAME, &fops);
}
static ssize_t device_read(struct file *filp,
char *buffer,
size_t length,
loff_t * offset)
{
volatile unsigned int counter;
long bytes_read;
char msg[BUF_LEN];
counter = get_cyclecount();
sprintf(msg, "%u", counter);
bytes_read = copy_to_user(buffer,msg,12);
if (bytes_read) printk(KERN_ALERT "error en contador.\n");
return bytes_read;
}