static ssize_t _print_profiling_states(gckKERNEL Kernel, gctUINT32 Count, char *buf) { gctUINT32 len = 0; gctUINT32 i = 0; gctUINT32 index = 0; gctUINT64 tick = 0; gceSTATUS status = gcvSTATUS_OK; gctUINT32 preTick, curTick; gckProfNode_PTR profNode = gcvNULL; gcmkONERROR(gckKERNEL_QueryLastProfNode(Kernel, &index, &profNode)); gcmkONERROR(gckOS_GetProfileTick(&tick)); preTick = gckOS_ProfileToMS(tick); len += sprintf(buf+len, " [GPU%d] tick = %d\n", Kernel->core, preTick); len += sprintf(buf+len, " index duration idle_ticks busy_ticks\n"); len += sprintf(buf+len, "-------+-------+-----------+-----------+\n"); for(i = 0; i < Count; i++) { gctUINT32 idx = (index + gcdPROFILE_NODES_NUM - i) % gcdPROFILE_NODES_NUM; curTick = profNode[idx].tick; len += sprintf(buf+len, "%2d(%3d):%8d%s%12d\n", i, idx, preTick-curTick, profNode[idx].idle ? "" : "\t ", curTick); preTick = curTick; } len += sprintf(buf+len, "\n"); return len; OnError: return sprintf(buf, "Failed to load stats for gpu %d\n", Kernel->core); }
/******************************************************************************* ** gckKERNEL_AddProcessDB ** ** Add a record to a process database. ** ** INPUT: ** ** gckKERNEL Kernel ** Pointer to a gckKERNEL object. ** ** gctUINT32 ProcessID ** Process ID used to identify the database. ** ** gceDATABASE_TYPE TYPE ** Type of the record to add. ** ** gctPOINTER Pointer ** Data of the record to add. ** ** gctPHYS_ADDR Physical ** Physical address of the record to add. ** ** gctSIZE_T Size ** Size of the record to add. ** ** OUTPUT: ** ** Nothing. */ gceSTATUS gckKERNEL_AddProcessDB( IN gckKERNEL Kernel, IN gctUINT32 ProcessID, IN gceDATABASE_TYPE Type, IN gctPOINTER Pointer, IN gctPHYS_ADDR Physical, IN gctSIZE_T Size ) { gceSTATUS status; gcsDATABASE_PTR database; gcsDATABASE_RECORD_PTR record = gcvNULL; gcsDATABASE_COUNTERS * count; gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x " "Physical=0x%x Size=%lu", Kernel, ProcessID, Type, Pointer, Physical, Size); /* Verify the arguments. */ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); /* Special case the idle record. */ if (Type == gcvDB_IDLE) { gctUINT64 time; /* Get the current profile time. */ gcmkONERROR(gckOS_GetProfileTick(&time)); if ((ProcessID == 0) && (Kernel->db->lastIdle != 0)) { /* Out of idle, adjust time it was idle. */ Kernel->db->idleTime += time - Kernel->db->lastIdle; Kernel->db->lastIdle = 0; } else if (ProcessID == 1) { /* Save current idle time. */ Kernel->db->lastIdle = time; } #if gcdDYNAMIC_SPEED { /* Test for first call. */ if (Kernel->db->lastSlowdown == 0) { /* Save milliseconds. */ Kernel->db->lastSlowdown = time; Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; } else { /* Compute ellapsed time in milliseconds. */ gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown); /* Test for end of period. */ if (delta >= gcdDYNAMIC_SPEED) { /* Compute number of idle milliseconds. */ gctUINT idle = gckOS_ProfileToMS( Kernel->db->idleTime - Kernel->db->lastSlowdownIdle); /* Broadcast to slow down the GPU. */ gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os, Kernel->hardware, idle, delta)); /* Save current time. */ Kernel->db->lastSlowdown = time; Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; } } } #endif /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; } /* Verify the arguments. */ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); /* Find the database. */ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); /* Create a new record in the database. */ gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record)); /* Initialize the record. */ record->kernel = Kernel; record->type = Type; record->data = Pointer; record->physical = Physical; record->bytes = Size; /* Get pointer to counters. */ switch (Type) { case gcvDB_VIDEO_MEMORY: count = &database->vidMem; break; case gcvDB_NON_PAGED: count = &database->nonPaged; break; case gcvDB_CONTIGUOUS: count = &database->contiguous; break; case gcvDB_MAP_MEMORY: count = &database->mapMemory; break; case gcvDB_MAP_USER_MEMORY: count = &database->mapUserMemory; break; default: count = gcvNULL; break; } if (count != gcvNULL) { /* Adjust counters. */ count->totalBytes += Size; count->bytes += Size; if (count->bytes > count->maxBytes) { count->maxBytes = count->bytes; } } /* Success. */ gcmkFOOTER_NO(); return gcvSTATUS_OK; OnError: /* Return the status. */ gcmkFOOTER(); return status; }
static ssize_t gc_proc_write( struct file *file, const char *buff, size_t len, loff_t *off) { char messages[256]; if(len > 256) len = 256; if(copy_from_user(messages, buff, len)) return -EFAULT; printk("\n"); if(strncmp(messages, "dutycycle", 9) == 0) { gctINT32 option; gcuDATABASE_INFO gpuIdle; static gctUINT64 startTime = 0; static gctUINT64 endTime = 0; gcmkVERIFY_OK(gckOS_ZeroMemory((gctPOINTER)&gpuIdle, gcmSIZEOF(gcuDATABASE_INFO))); sscanf(messages+9, "%d", &option); switch(option) { case 0: gcmkVERIFY_OK(gckOS_GetProfileTick(&startTime)); gcmkVERIFY_OK(gckKERNEL_QueryDutyCycleDB(galDevice->kernels[gcvCORE_MAJOR], gcvTRUE, &gpuIdle)); gpuIdle.time = 0; endTime = 0; break; case 1: gcmkVERIFY_OK(gckKERNEL_QueryDutyCycleDB(galDevice->kernels[gcvCORE_MAJOR], gcvFALSE, &gpuIdle)); gcmkVERIFY_OK(gckOS_GetProfileTick(&endTime)); break; default: printk(KERN_INFO "usage: echo dutycycle [0|1] > /proc/driver/gc\n"); } if(startTime != 0 && endTime != 0) { gctUINT64 delta = endTime - startTime; gctUINT32 per = 100 - 100 * gckOS_ProfileToMS(gpuIdle.time) / gckOS_ProfileToMS(delta); printk(KERN_INFO "\n %%GPU START END DELTA IDLE\n"); printk(KERN_INFO "%5u%% %8u %8u %8u %8u\n\n", per, gckOS_ProfileToMS(startTime), gckOS_ProfileToMS(endTime), gckOS_ProfileToMS(delta), gckOS_ProfileToMS(gpuIdle.time)); } } else if(strncmp(messages, "reg", 3) == 0) { gctINT32 option; gctUINT32 idle, address, clockControl; sscanf(messages+3, "%d", &option); switch(option) { case 1: /* Read the current FE address. */ gckOS_ReadRegisterEx(galDevice->os, galDevice->kernels[0]->hardware->core, 0x00664, &address); gcmkPRINT("address: 0x%2x\n", address); break; case 2: /* Read idle register. */ gckOS_ReadRegisterEx(galDevice->os, galDevice->kernels[0]->hardware->core, 0x00004, &idle); gcmkPRINT("idle: 0x%2x\n", idle); break; case 3: gckOS_ReadRegisterEx(galDevice->os, gcvCORE_MAJOR, 0x00000, &clockControl); gcmkPRINT("clockControl: 0x%2x\n", clockControl); break; default: printk(KERN_INFO "usage: echo reg [1|2|3] > /proc/driver/gc\n"); } } else if(strncmp(messages, "help", 4) == 0) { printk("Supported options:\n" "dutycycle measure dutycycle in a period\n" "reg enable debugging for register reading\n" "help show this help page\n" "\n"); } else { gcmkPRINT("unknown echo\n"); } printk("\n"); return len; }