Created
January 30, 2012 15:31
-
-
Save shimada-k/1704983 to your computer and use it in GitHub Desktop.
lbバイナリを解析するプログラム
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
#include <stdio.h> | |
#include <stdlib.h> /* exit(3) */ | |
#include <unistd.h> /* sysconf(3) */ | |
#include <string.h> /* memset(3) */ | |
struct object{ | |
int src_cpu, dst_cpu; | |
long pid; | |
long sec, usec; | |
}; | |
/*================================================================================ | |
ファイルを引数で指定して、解析し、CSVを出力するプログラム | |
CSVはカレントディレクトリに出力される | |
このプログラムはkprofiled::trace_lb_entryと協調して動作するので | |
struct objectを変更した場合は同期させておくこと | |
Usage: | |
./lb_analysis "入力元(オブジェクトファイル名)" | |
==================================================================================*/ | |
#define NR_CPUS 8 | |
#define MAX_NR_HOLD 32 | |
struct pid_loop{ | |
unsigned int loop; | |
int src_cpu, dst_cpu; | |
}; | |
struct summary_csv{ | |
unsigned int rt_count, fl_count; | |
unsigned int rt_decomposition[NR_CPUS][NR_CPUS]; | |
}; | |
/* CSVに出力 */ | |
static void print_csv_summary(FILE *f_csv, struct summary_csv *summary) | |
{ | |
int i, j, k, l; | |
fprintf(f_csv, "Round-Trip\n\n"); | |
/* HOLD毎の回数を出力 */ | |
fprintf(f_csv, ",Times of Round-Trip\n"); | |
for(i = 0; i < MAX_NR_HOLD - 1; i++){ | |
fprintf(f_csv, "%d,%d\n", i + 1, summary[i + 1].rt_count); | |
} | |
fprintf(f_csv, "\n"); | |
for(i = 0; i < MAX_NR_HOLD; i++){ | |
if(summary[i].rt_count > 0){ | |
/* HOLD毎のDecompositionを出力 */ | |
fprintf(f_csv, "Round-Trip[%d]\n", i); | |
for(l = 0; l < NR_CPUS; l++){ | |
fprintf(f_csv, ",CPU%d", l); | |
} | |
fprintf(f_csv, "\n"); | |
for(j = 0; j < NR_CPUS; j++){ | |
fprintf(f_csv, "CPU%d,", j); | |
for(k = 0; k < NR_CPUS; k++){ | |
fprintf(f_csv, "%d,", summary[i].rt_decomposition[j][k]); | |
} | |
fprintf(f_csv, "\n"); | |
} | |
fprintf(f_csv, "\n"); | |
} | |
} | |
fprintf(f_csv, "\n"); | |
/* Float現象の回数を出力 */ | |
fprintf(f_csv, ",Times of Float\n\n"); | |
for(i = 0; i < MAX_NR_HOLD - 1; i++){ | |
fprintf(f_csv, "%d,%d\n", i + 1, summary[i + 1].fl_count); | |
} | |
fprintf(f_csv, "\n"); | |
} | |
/* wraped_objectのflagに入る変数 */ | |
#define FLAG_NO_REFER 0 | |
#define FLAG_PASSED -1 | |
/* 解析のためにobjectをラップした構造 */ | |
struct wraped_object{ | |
struct object obj, rt_origin, fl_origin; | |
int rt_flag, fl_flag; /* パスの長さが格納される */ | |
}; | |
/* 比較のために1回のロードバランスのエントリを保存しておく領域 */ | |
struct obj_buffer{ | |
struct wraped_object *buffer; | |
int index; | |
}; | |
#define BURST_LENGTH 450 | |
#ifdef DEBUG | |
/* | |
objectの内容を標準出力に表示する関数 | |
@object 表示する対象のobject | |
*/ | |
static void __debug_print_object(const struct object *object) | |
{ | |
printf("[%lu.%lu] PID:%lu, CPU%d ==> CPU%d\n", object->sec, object->usec, | |
object->pid, object->src_cpu, object->dst_cpu); | |
} | |
#endif | |
/* | |
バースト転送を@buffに記録する関数 | |
@f_obj オブジェクトファイルのFILEアドレス | |
@buff 記録する先のバッファ領域のアドレス | |
@next_head バーストが終了して次のバーストの先頭のobject | |
return -1:エラー それ以外:読み込んだバーストで発生したobjectの数 | |
*/ | |
static int fetch_burst(FILE *f_obj, struct obj_buffer *buff, struct object *next_head) | |
{ | |
int burst_length = 0; | |
if(buff->index != 1){ | |
printf("エラー:最初の1個がbuffに入ってない index:%d\n", buff->index); | |
return -1; | |
} | |
while(1){ /* struct objectが読み込める限りloop */ | |
if(fread(next_head, sizeof(struct object), 1, f_obj) == 1){ | |
burst_length++; | |
} | |
else{ | |
break; | |
} | |
if(next_head->src_cpu == buff->buffer[buff->index - 1].obj.src_cpu | |
&& next_head->dst_cpu == buff->buffer[buff->index - 1].obj.dst_cpu){ /* バースト転送の途中 */ | |
if(buff->index < BURST_LENGTH){ | |
buff->buffer[buff->index].obj = *next_head; | |
buff->index++; | |
} | |
else{ | |
printf("エラー:もっとバッファを増やせ buff->index:%d\n", buff->index); | |
} | |
} | |
else{ /* バースト転送が終了した */ | |
break; | |
} | |
} | |
return burst_length; | |
} | |
/* | |
lastにfetchを格納してバッファを入れ替える関数 | |
@fetch ここに新しいデータが入っている | |
@last こっちは古いデータが入っている | |
lastのバッファを次のfetchで使うために入れ替える。逆に現状fetchのデータはlastになる | |
*/ | |
static void swap_buffer(struct obj_buffer *fetch, struct obj_buffer *last) | |
{ | |
struct wraped_object *swap_ptr; | |
/*================================================================================== | |
ドロップアウトするobjectを出力したしドロップアウトしないobjectの情報はbuff_fetchに | |
メモしたのでbuff_lastはクリアしていい | |
====================================================================================*/ | |
memset(last->buffer, 0, BURST_LENGTH * sizeof(struct wraped_object)); | |
last->index = 0; | |
swap_ptr = last->buffer; /* buff_lastはクリアされている */ | |
last->buffer = fetch->buffer; | |
last->index = fetch->index; | |
fetch->buffer = swap_ptr; | |
fetch->index = 0; | |
} | |
/* | |
objectがキャッシュをまたいだロードバランスかどうか | |
@obj 検査するobjectのアドレス | |
return またいでいる:1 またいでいない:0 | |
*/ | |
static int cache_crossed(struct object *obj) | |
{ | |
if(obj->src_cpu == 0 && obj->dst_cpu == 4){ | |
return 0; | |
} | |
else if(obj->src_cpu == 1 && obj->dst_cpu == 5){ | |
return 0; | |
} | |
else if(obj->src_cpu == 2 && obj->dst_cpu == 6){ | |
return 0; | |
} | |
else if(obj->src_cpu == 3 && obj->dst_cpu == 7){ | |
return 0; | |
} | |
else{ | |
return 1; | |
} | |
} | |
/* | |
解析アルゴリズムのメイン | |
@f_obj objectファイルのFILE構造体 | |
@round_trip Round-Trip現象のデータを格納する配列 | |
return 読み込めたobjectの総数 | |
*/ | |
static int analyze_main(FILE *f_obj, struct summary_csv *summary) | |
{ | |
int i, j, fetch = 0, nr_total_object = 0; | |
struct object temp; | |
struct obj_buffer buff_fetch, buff_last; | |
memset(&buff_fetch, 0, sizeof(struct obj_buffer)); | |
memset(&buff_last, 0, sizeof(struct obj_buffer)); | |
/* メモリ確保&初期化 */ | |
buff_fetch.buffer = calloc(BURST_LENGTH, sizeof(struct wraped_object)); | |
buff_last.buffer = calloc(BURST_LENGTH, sizeof(struct wraped_object)); | |
/* 最初の一回は無条件に格納しておく */ | |
fread(&temp, sizeof(struct object), 1, f_obj); | |
buff_last.buffer[buff_last.index].obj = temp; | |
buff_last.index++; | |
fetch = fetch_burst(f_obj, &buff_last, &temp); | |
printf("buff_fetch.index:%d\n", buff_fetch.index); | |
if(fetch > 0){ /* 正常終了だったら */ | |
/* 次にbuff_fetchするために1個入れとかないといけない */ | |
buff_fetch.buffer[buff_fetch.index].obj = temp; | |
buff_fetch.index++; | |
nr_total_object += fetch; | |
} | |
else{ | |
if(fetch == -1){ | |
puts("エラー"); | |
} | |
else if(fetch == 0){ | |
puts("もう読めないぽ"); | |
} | |
} | |
fetch = fetch_burst(f_obj, &buff_fetch, &temp); | |
/*========================================================================== | |
ここまででbuff_fetchとbuff_lastにはデータが満たされているので、比較ができる | |
============================================================================*/ | |
while(1){ | |
if(buff_fetch.buffer[0].obj.src_cpu == buff_last.buffer[0].obj.dst_cpu){ | |
if(buff_fetch.buffer[0].obj.dst_cpu == buff_last.buffer[0].obj.src_cpu){ | |
for(i = 0; i < buff_fetch.index; i++){ | |
for(j = 0; j < buff_last.index && buff_last.buffer[j].rt_flag != FLAG_PASSED; j++){ | |
if(buff_fetch.buffer[i].obj.pid == buff_last.buffer[j].obj.pid){ | |
/* Round-Tripを検出 */ | |
buff_fetch.buffer[i].rt_flag = buff_last.buffer[j].rt_flag + 1; | |
buff_fetch.buffer[i].rt_origin = buff_last.buffer[j].obj; | |
buff_last.buffer[j].rt_flag = FLAG_PASSED; | |
} | |
} | |
} | |
} | |
else if(buff_fetch.buffer[0].obj.dst_cpu != buff_last.buffer[0].obj.src_cpu){ | |
#ifdef DEBUG | |
printf("last[CPU%d-->CPU%d] fetch[CPU%d-->CPU%d]\n", buff_last.buffer[0].obj.src_cpu, | |
buff_last.buffer[0].obj.dst_cpu, buff_fetch.buffer[0].obj.src_cpu, | |
buff_fetch.buffer[0].obj.dst_cpu); | |
#endif | |
for(i = 0; i < buff_fetch.index; i++){ | |
for(j = 0; j < buff_last.index && buff_last.buffer[j].fl_flag != FLAG_PASSED; j++){ | |
if(buff_fetch.buffer[i].obj.pid == buff_last.buffer[j].obj.pid){ | |
/* Floatを検出 */ | |
buff_fetch.buffer[i].fl_flag = buff_last.buffer[j].fl_flag + 1; | |
buff_fetch.buffer[i].fl_origin = buff_last.buffer[j].obj; | |
#ifdef DEBUG | |
__debug_print_object(&buff_fetch.buffer[i].fl_origin); | |
#endif | |
buff_last.buffer[j].fl_flag = FLAG_PASSED; | |
} | |
} | |
} | |
} | |
} | |
/* ドロップアウトするobjectたち */ | |
for(i = 0; i < buff_last.index; i++){ | |
struct wraped_object *wobj; | |
if(buff_last.buffer[i].rt_flag > 0){ /* flagに1以上の数が入っていたらドロップアウト */ | |
wobj = &buff_last.buffer[i]; | |
//__debug_print_object(&buff_last.buffer[i].obj); | |
//printf("flag:%d\n", buff_last.buffer[i].flag); | |
if(buff_last.buffer[i].rt_flag > MAX_NR_HOLD){ | |
puts("もっとMAX_NR_HOLDを増やさないといけない"); | |
} | |
else{ | |
/* summary_csv_rtに記録 */ | |
summary[wobj->rt_flag].rt_count++; | |
summary[wobj->rt_flag].rt_decomposition[wobj->obj.src_cpu][wobj->obj.dst_cpu] += wobj->rt_flag; | |
} | |
} | |
else if(buff_last.buffer[i].fl_flag > 0){ /* flagに1以上の数が入っていたらドロップアウト */ | |
wobj = &buff_last.buffer[i]; | |
//__debug_print_object(&buff_last.buffer[i].obj); | |
//printf("flag:%d\n", buff_last.buffer[i].flag); | |
if(buff_last.buffer[i].fl_flag > MAX_NR_HOLD){ | |
puts("もっとMAX_NR_HOLDを増やさないといけない"); | |
} | |
else{ | |
/* flに記録 */ | |
summary[wobj->fl_flag].fl_count++; | |
} | |
} | |
} | |
/* buff_lastとbuff_fetchのbufferを入れ替える */ | |
swap_buffer(&buff_fetch, &buff_last); | |
/* 次のバーストをbuff_fetchに格納する */ | |
buff_fetch.buffer[buff_fetch.index].obj = temp; | |
buff_fetch.index++; | |
fetch = fetch_burst(f_obj, &buff_fetch, &temp); | |
if(fetch <= 0){ /* 正常終了だったら */ | |
if(fetch == -1){ | |
puts("エラー"); | |
} | |
else if(fetch == 0){ | |
puts("もう読めないぽ"); | |
break; | |
} | |
} | |
else{ | |
nr_total_object += fetch; | |
} | |
} | |
/* メモリを解放 */ | |
free(buff_fetch.buffer); | |
free(buff_last.buffer); | |
return nr_total_object; | |
} | |
#define MAX_PATH_LEN 64 | |
int main(int argc, char *argv[]) | |
{ | |
int counter, i, j; | |
struct object obj; | |
struct summary_csv summary[MAX_NR_HOLD]; | |
unsigned int lb_decomposition[NR_CPUS][NR_CPUS]; | |
char output_path[MAX_PATH_LEN]; | |
FILE *f_csv = NULL, *f_obj = NULL; | |
/* 格納用配列をクリア */ | |
memset(summary, 0, MAX_NR_HOLD * sizeof(struct summary_csv)); | |
memset(lb_decomposition, 0, NR_CPUS * NR_CPUS * sizeof(unsigned int)); | |
if(argc == 2){ | |
if((f_obj = fopen(argv[1], "rb")) == NULL){ | |
puts("エラー"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
else{ | |
printf("引数でobjectファイルを指定してください\n"); | |
return 0; | |
} | |
sprintf(output_path, "./%s.csv", argv[1]); | |
f_csv = fopen(output_path, "w"); | |
counter = analyze_main(f_obj, summary); | |
fprintf(f_csv, "counter = %d\n\n", counter); | |
print_csv_summary(f_csv, summary); | |
/* 一旦最初に戻す */ | |
fseek(f_obj, SEEK_SET, 0); | |
int index = 0; | |
while(fread(&obj, sizeof(struct object), 1, f_obj) == 1){ | |
index++; | |
/* データが壊れていることも考慮して */ | |
if(obj.src_cpu < NR_CPUS && obj.dst_cpu < NR_CPUS){ | |
lb_decomposition[obj.src_cpu][obj.dst_cpu]++; | |
} | |
else{ | |
printf("%s is destroied:%d\n", argv[1], index); | |
#ifdef DEBUG | |
__debug_print_object(&obj); | |
#endif | |
} | |
} | |
puts("hoge"); | |
fprintf(f_csv, "total_lb_decomposition\n"); | |
for(i = 0; i < NR_CPUS; i++){ | |
fprintf(f_csv, ",CPU%d", i); | |
} | |
fprintf(f_csv, "\n"); | |
for(i = 0; i < NR_CPUS; i++){ | |
fprintf(f_csv, "CPU%d,", i); | |
for(j = 0; j < NR_CPUS; j++){ | |
fprintf(f_csv, "%d,", lb_decomposition[i][j]); | |
} | |
fprintf(f_csv, "\n"); | |
} | |
fprintf(f_csv, "\n"); | |
fclose(f_obj); | |
fclose(f_csv); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment