Skip to content

Instantly share code, notes, and snippets.

@shimada-k
Created January 30, 2012 15:31
Show Gist options
  • Save shimada-k/1704983 to your computer and use it in GitHub Desktop.
Save shimada-k/1704983 to your computer and use it in GitHub Desktop.
lbバイナリを解析するプログラム
#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