/****************************************************** /* /* consume ratio freq /* to consume cpu time at ratio and frequency. /* The original code was from Peter Zijlstra, /* the kernal.org maintainer of the sched /* area of the kernel code. /* /* consume.c Smythies 2104.07.31 /* Credit Stratos Karafotis. /* add total sleep time. /* /* consume.c Smythies 2104.07.31 /* Credit Stratos Karafotis. /* Switch from usleep to nanosleep. /* It is more accurate and usleep might /* become depricated. /* /* consume.c Smythies 2104.07.31 /* put consume.c (fixed load) and consume1.c /* (fixed work packets) together into /* one program, with a command line option /* as to which method to run. /* So as to not break a bunch of scrtips, /* default to fixed load if the option is /* is not specified. /* /* consume1.c Smythies 2014.07.31 /* Due to response time, some overruns might /* occur, and such is normal and it should /* catch up. Add a loop counter to make it /* obvious when it doesn't catch up. /* Typically this is useful when doing ramp up /* tests, otherwise one might not know what to /* expect for a normal loop count. /* /* consume1.c Smythies 2014.07.05 /* Since fixed work packet calibration is /* based on the minimum pstate, fractions /* of over 100% are allowed. /* /* consume1.c Smythies 2014.06.27 /* As it turns out, my processor uses more /* energy for a fixed work packet at higher /* CPU clock rates. /* I get at least one overrun always the first /* time after a re-boot. Change it from a once /* only flag to a counter. /* Eliminate the floating point processor from /* fixed packet loop and get much better /* granularity for the calibration. /* /* consume1.c Smythies 2014.06.24 /* Attempt to make fixed work packet per period. /* The point is to finish faster for higher /* CPU clock rates, and to use less energy. /* /* consume.c Smythies 2014.06.24 /* Exit more accurately. /* /* consume.c Smythies 2014.06.07 /* Fix dense math issue with elapsed time. /* /* consume.c Smythies 2014.05.31 /* Even though I don't like the extra overhead, /* List its PID and some times to assist /* correlating with "perf record" data. /* /* consume.c Smythies 2014.05.05 /* Fix usage message. /* /* consume.c Smythies 2013.11.04 /* Add a time to execute parameter. /* allow the fraction to be as low as 0.5 percent /* /* consume.c Smythies 2012.06.27 /* More precision desired. Switch to doubles for /* run time parameters. /* /* consume.c Smythies 2012.06.23 /* I think in frequency for this stuff, so change /* the run time parameter from period to frequency. /* Make it not optional. /* /* consume.c Smythies 2012.06.23 /* First just try to compile the code as sent /* from Peter Zijlstra. /* But converted to my coding standards (which will /* annoy Peter if it ever gets sent back). /* /******************************************************/ // for the fixed work packet stuff, calibration for your // processor is required. // lock your processor at the minimum pstate and then // set this number as large as possible witrhout overruns // at a low sleep / load rate. // (Note: we may change to calibrate at max non-turbo pstate) // Of course, the calibration might need to checked // as the compiler or kernel evolves. // For intel Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz #define CALIBRATION 151 #include #include #include #include #include #include int fixed_workpackets; void __usleep(int us) { struct timespec time; time.tv_sec = 0; time.tv_nsec = us * 1000; while(nanosleep(&time, &time) == -1 && errno == EINTR) continue; } unsigned long long stamp(void){ struct timeval tv; gettimeofday(&tv, NULL); return (unsigned long long)tv.tv_sec * 1000000 + tv.tv_usec; } /* endprocedure */ void consume(int spin, int total, int elapsed){ unsigned long long begin, now, start, lelapsed, total_sleep, current_sleep; int i, j, k; int overruns, loop_count; overruns = 0; loop_count = 0; total_sleep = 0; begin = stamp(); start = begin; now = begin; lelapsed = (unsigned long long)elapsed * (unsigned long long) 1000000; while((long long)(now - start) < lelapsed) { /* for the requested time */ if(fixed_workpackets == 0){ if ((long long)(now - begin) > spin) { current_sleep = total - spin; total_sleep = total_sleep + current_sleep; __usleep(current_sleep); begin += total; } /* endif */ } else { for(i = 0; i < spin; i++){ /* do a fixed packet of work */ for(j = 0; j < CALIBRATION; j++){ k = (i + j) / 25; k = k + i + j; } /* endfor */ } /* endfor */ now = stamp(); if ((long long)(now - begin) < total ) { current_sleep = total - (now - begin); total_sleep = total_sleep + current_sleep; __usleep(current_sleep); } else { overruns++; // printf("\n Overrun: %llu %d\n", now - begin, total); } /* endif */ loop_count++; begin += total; } /* endif */ now = stamp(); } /* endwhile */ printf(": Elapsed: %llu Now: %llu Total sleep: %llu", (now - start), now, total_sleep); if(fixed_workpackets == 0){ printf("\n"); } else { printf(" Overruns: %d Loops: %d\n", overruns, loop_count); } /* endif */ } /* endprocedure */ int main(int argc, char **argv){ double frac, freq, duration, period; printf("consume: %s %s %s PID: %d", argv[1], argv[2], argv[3], getpid()); switch(argc){ case 4: frac = atof(argv[1]); freq = atof(argv[2]); duration = atof(argv[3]); fixed_workpackets = 0; break; case 5: frac = atof(argv[1]); freq = atof(argv[2]); duration = atof(argv[3]); fixed_workpackets = atoi(argv[4]); break; default: fprintf(stderr, "%s [optional fixed workpackets]\n frac -- [0.5-100.0] %% of time to burn\n freq -- [hz] (min 1.0) frequency of burn/sleep cycle\n duration -- [seconds] (0.0 means 1 day) time for program to run\n optional fixed workpackets -- any non-zero integer means used fixed workpackets instead of fixed load (and then loads >100%% are allowed\n", argv[0]); return -1; } /* endcase */ if(fixed_workpackets == 0){ printf(" - fixed load method"); } else { printf(" - fixed workpacket method"); } /* endif */ /* printf("consume: %lf %lf %lf\n", frac, freq, duration); /* */ if ((frac > 100.0) && (fixed_workpackets == 0)){ frac = 100.0; } /* endif */ if (frac < 0.50){ frac = 0.50; } /* endif */ if (freq < 1.0){ freq = 1.0; } /* endif */ if (duration <= 0.0){ duration = 86400.0; } /* endif */ period = 1000000.0 / freq; /* printf("consume: %lf %lf %lf %lf\n", frac, freq, period, duration); /* */ consume((int)(period * frac / 100.0 + 0.5), (int)(period + 0.5), (int)(duration + 0.5)); return 0; } /* endprocedure */