// Real timer filter bool driver::perfTimerEvent(IOTimerEventSource *src, int count) { uint64_t msr; uint32_t vid; uint32_t next_check_delay; uint32_t wantspeed,wantstep; long i,idle,used,total; if (driverStatus != driverDrive) return(false); //ok, so we're using adaptive mode.. if (get_cpu_ticks(&idle, &total)) fail("get_cpu_load"); // Used = % used x 10 used = ((total-idle)*1000)/total; // If used > 95% we can't really guess how much is needed, so step to highest speed if (used>=950) wantspeed=speedstep_cpu_setting[num_speeds-1].cpuMhz; // Otherwise wantspeed is the ideal frequency to maintain idle % target else wantspeed = (speedstep_cpu_setting[stepCurrent].cpuMhz * (used+1)) / TARGET_CPULOAD; if (wantspeed>=speedstep_cpu_setting[num_speeds-1].cpuMhz) wantstep = num_speeds-1; // We want something higher than our highest else if (wantspeed<=speedstep_cpu_setting[0].cpuMhz) wantstep = 0; // We want something lower than our lowest // Otherwise, find the best step else for (i = 0; i < (num_speeds-1); i++) if ((wantspeed >= speedstep_cpu_setting[i].cpuMhz) && (wantspeed < speedstep_cpu_setting[i+1].cpuMhz)) wantstep=i; //dbg("pctused=%u idle=%u total=%u wantspeed=%u wantstep=%u\n",used,idle,total,wantspeed,wantstep); if (wantstep == stepCurrent) goto check_soon; stepCurrent = wantstep; // Assume we got the one we wanted eist_update_all_cpus(speedstep_cpu_setting[wantstep].VID); // IOSleep(1); msr = rdmsr64(MSR_PERF_CTL); vid = msr & 0xFFFF; dbg("Stepping to %u pctused=%u VID=0x%04x\n",speedstep_cpu_setting[wantstep].cpuMhz,used,vid); perfTimer->setTimeoutMS(512 * (wantstep+1)); // Make the delay until the next check proportional to the speed we picked return(true); perfTimer->setTimeoutMS(1024); success: return(true); check_soon: perfTimer->setTimeoutMS(512); return(true); fail: return(false); }
/* called on every vsync */ void pl_frame_limit(void) { static struct timeval tv_old, tv_expect; static int vsync_cnt_prev; struct timeval now; int diff, usadj; vsync_cnt++; /* doing input here because the pad is polled * thousands of times per frame for some reason */ update_input(); pcnt_end(PCNT_ALL); gettimeofday(&now, 0); if (now.tv_sec != tv_old.tv_sec) { diff = tvdiff(now, tv_old); vsps_cur = 0.0f; if (0 < diff && diff < 2000000) vsps_cur = 1000000.0f * (vsync_cnt - vsync_cnt_prev) / diff; vsync_cnt_prev = vsync_cnt; flips_per_sec = flip_cnt; flip_cnt = 0; tv_old = now; if (g_opts & OPT_SHOWCPU) tick_per_sec = get_cpu_ticks(); if (hud_new_msg > 0) { hud_new_msg--; if (hud_new_msg == 0) hud_msg[0] = 0; } } #ifdef PCNT static int ya_vsync_count; if (++ya_vsync_count == PCNT_FRAMES) { pcnt_print(vsps_cur); ya_vsync_count = 0; } #endif tvadd(tv_expect, pl_frame_interval); diff = tvdiff(tv_expect, now); if (diff > MAX_LAG_FRAMES * pl_frame_interval || diff < -MAX_LAG_FRAMES * pl_frame_interval) { //printf("pl_frame_limit reset, diff=%d, iv %d\n", diff, pl_frame_interval); tv_expect = now; diff = 0; // try to align with vsync usadj = vsync_usec_time; while (usadj < tv_expect.tv_usec - pl_frame_interval) usadj += pl_frame_interval; tv_expect.tv_usec = usadj; } if (!(g_opts & OPT_NO_FRAMELIM) && diff > pl_frame_interval) { // yay for working usleep on pandora! //printf("usleep %d\n", diff - pl_frame_interval / 2); usleep(diff - pl_frame_interval / 2); } if (UseFrameSkip) { if (diff < -pl_frame_interval) { // P.E.Op.S. makes skip decision based on this fps_skip = 1.0f; plugin_skip_advice = 1; } else if (diff >= 0) { fps_skip = 100.0f; plugin_skip_advice = 0; } } pcnt_start(PCNT_ALL); }