Last active
August 29, 2015 14:22
-
-
Save frma71/706410acbd31556dbbfa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This is a tiny application to demonstrate the bug where the linux kernel reports | |
* load far greater then 100% for a single thread. It assumes CONFIG_HZ_100 and probably | |
* that NO_HZ is disabled. Since the kernel is sampling it doesn't reproduce the problem | |
* to its full extent every time, but on my arndale board it does so at least nine times | |
* out of ten. | |
* | |
* Compile with: gcc -o loadbug loadbug.c | |
*/ | |
#include <stdio.h> | |
#include <time.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <sys/select.h> | |
#include <sys/times.h> | |
#include <assert.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
uint64_t clk(void) { | |
struct timespec ts; | |
int rv; | |
rv = clock_gettime(CLOCK_MONOTONIC, &ts); | |
assert(rv == 0); | |
return (uint64_t)ts.tv_sec*1000000000ULL + ts.tv_nsec; | |
} | |
void wait_for_tick(void) { | |
clock_t now = times(0); | |
while(now == times(0)); | |
} | |
void busydelay(uint64_t ns) { | |
volatile int i; | |
uint64_t start = clk(); | |
while(clk() - start < ns) | |
for(i = 0; i < 2000; i++) {} | |
} | |
void sysbusydelay(uint64_t ns) { | |
static int fd = -1; | |
static char buff[4096*100]; | |
uint64_t start; | |
if(fd == -1) | |
fd = open("/dev/zero", O_RDONLY); | |
assert(fd >= 0); | |
start = clk(); | |
while(clk() - start < ns) { | |
read(fd, buff, sizeof(buff)); | |
} | |
} | |
void clk_sleep_until(uint64_t t) { | |
struct timespec ts; | |
int rv; | |
ts.tv_sec = t/1000000000ULL; | |
ts.tv_nsec = t - ts.tv_sec*1000000000ULL; | |
rv = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, 0); | |
assert(rv == 0); | |
} | |
#define NS_PER_US 1000ULL | |
#define NS_PER_MS 1000000ULL | |
#define NS_PER_SEC 1000000000ULL | |
#define NS_PER_TICK (10*NS_PER_MS) | |
int main(void) { | |
uint64_t t; | |
int i; | |
/* First synchronize with the tick | |
*/ | |
wait_for_tick(); | |
/* Wait until 1ms before the next tick. | |
*/ | |
t = clk() + 9*NS_PER_MS; | |
clk_sleep_until(t); | |
while(1) { | |
/* Let system clock sample us once in system mode | |
*/ | |
sysbusydelay(2*NS_PER_MS); /* sys-time during tick */ | |
t += NS_PER_TICK; | |
clk_sleep_until(t); | |
/* ... and keep loading but not during tick-sampling | |
*/ | |
for(i = 0; i < 10*100-1; i++) { | |
clk_sleep_until(t+2*NS_PER_MS); /* Make sure we are idle during tick() sampling */ | |
busydelay(2*NS_PER_MS); | |
t += NS_PER_TICK; | |
clk_sleep_until(t); | |
} | |
printf("switch to umode\n"); | |
/* Now utime hits every tick but the actual load is still 10% | |
*/ | |
for(i = 0; i < 10*100; i++) { | |
busydelay(2*NS_PER_MS); /* Make sure we are running in user mode during tick() sampling */ | |
t += NS_PER_TICK; | |
clk_sleep_until(t); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment