graph.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. // graph creation is enabled
  4. // #define ENABLE_GRAPH
  5. #ifdef ENABLE_GRAPH
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #ifndef _WIN32
  10. #include <unistd.h>
  11. #endif
  12. #ifdef MINGW
  13. #include <io.h>
  14. #endif
  15. #include "../common/core.h"
  16. #include "../common/timer.h"
  17. #include "../common/grfio.h"
  18. #include "../common/malloc.h"
  19. #include "graph.h"
  20. struct graph {
  21. int width;
  22. int height;
  23. int pallet_count;
  24. int png_len;
  25. int png_dirty;
  26. unsigned char* raw_data;
  27. unsigned char* png_data;
  28. int * graph_value;
  29. int graph_max;
  30. };
  31. void graph_write_dword(unsigned char* p,unsigned int v) {
  32. p[0] = (unsigned char)((v >> 24) & 0xFF);
  33. p[1] = (unsigned char)((v >> 16) & 0xFF);
  34. p[2] = (unsigned char)((v >> 8) & 0xFF);
  35. p[3] = (unsigned char)(v & 0xFF);
  36. }
  37. struct graph* graph_create(unsigned int x,unsigned int y) {
  38. struct graph *g = (struct graph*)aCalloc(sizeof(struct graph),1);
  39. if(g == NULL) return NULL;
  40. // 256 * 3 : パレットデータ
  41. // x * y * 2 : イメージのバッファ
  42. // 256 : チャンクデータなどの予備
  43. g->png_data = (unsigned char *) aMalloc(4 * 256 + (x + 1) * y * 2);
  44. g->raw_data = (unsigned char *) aCalloc( (x + 1) * y , 1);
  45. memcpy(
  46. g->png_data,
  47. "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52"
  48. "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x03\x00\x00\x00\xFF\xFF\xFF"
  49. "\xFF\x00\x00\x00\x03\x50\x4C\x54\x45\xFF\xFF\xFF\xA7\xC4\x1B\xC8",0x30
  50. );
  51. graph_write_dword(g->png_data + 0x10,x);
  52. graph_write_dword(g->png_data + 0x14,y);
  53. graph_write_dword(g->png_data + 0x1D,grfio_crc32(g->png_data+0x0C,0x11));
  54. g->pallet_count = 1;
  55. g->width = x;
  56. g->height = y;
  57. g->png_dirty = 1;
  58. g->graph_value = (int *) aCalloc(x,sizeof(int));
  59. g->graph_max = 1;
  60. return g;
  61. }
  62. void graph_pallet(struct graph* g, int index,unsigned long c) {
  63. if(g == NULL || c >= 256) return;
  64. if(g->pallet_count <= index) {
  65. memset(g->png_data + 0x29 + 3 * g->pallet_count,0,(index - g->pallet_count) * 3);
  66. g->pallet_count = index + 1;
  67. }
  68. g->png_data[0x29 + index * 3 ] = (unsigned char)((c >> 16) & 0xFF); // R
  69. g->png_data[0x29 + index * 3 + 1] = (unsigned char)((c >> 8) & 0xFF); // G
  70. g->png_data[0x29 + index * 3 + 2] = (unsigned char)( c & 0xFF); // B
  71. graph_write_dword(g->png_data + 0x21,g->pallet_count * 3);
  72. graph_write_dword(
  73. g->png_data + 0x29 + g->pallet_count * 3,
  74. grfio_crc32(g->png_data + 0x25,g->pallet_count * 3 + 4)
  75. );
  76. g->png_dirty = 1;
  77. }
  78. void graph_setpixel(struct graph* g,int x,int y,int color) {
  79. if(g == NULL || color >= 256) { return; }
  80. if(x < 0) x = 0;
  81. if(y < 0) y = 0;
  82. if(x >= g->width) { x = g->width - 1; }
  83. if(y >= g->height) { y = g->height - 1; }
  84. if(color >= g->pallet_count) { graph_pallet(g,color,graph_rgb(0,0,0)); }
  85. g->raw_data[y * (g->width + 1) + x + 1] = (unsigned char)color;
  86. g->png_dirty = 1;
  87. }
  88. int graph_getpixel(struct graph* g,int x,int y) {
  89. if(x < 0) x = 0;
  90. if(y < 0) y = 0;
  91. if(x >= g->width) { x = g->width - 1; }
  92. if(y >= g->height) { y = g->height - 1; }
  93. return g->raw_data[y * (g->width + 1) + x + 1];
  94. }
  95. const unsigned char* graph_output(struct graph* g,int *len) {
  96. unsigned long inflate_len;
  97. unsigned char *p;
  98. if(g == NULL) return NULL;
  99. if(g->png_dirty == 0) {
  100. *len = g->png_len;
  101. return g->png_data;
  102. }
  103. p = g->png_data + 0x2D + 3 * g->pallet_count;
  104. inflate_len = 2 * (g->width + 1) * g->height;
  105. memcpy(p + 4,"IDAT",4);
  106. encode_zip(p + 8,&inflate_len,g->raw_data,(g->width + 1) * g->height);
  107. graph_write_dword(p,inflate_len);
  108. graph_write_dword(p + 8 + inflate_len,grfio_crc32(p + 4, inflate_len + 4));
  109. p += 0x0C + inflate_len;
  110. memcpy(p,"\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82",0x0C);
  111. p += 0x0C;
  112. g->png_len = p - g->png_data;
  113. g->png_dirty = 0;
  114. *len = g->png_len;
  115. return g->png_data;
  116. }
  117. void graph_free(struct graph* g) {
  118. if(g != NULL) {
  119. aFree(g->png_data);
  120. aFree(g->raw_data);
  121. aFree(g->graph_value);
  122. aFree(g);
  123. }
  124. }
  125. // とりあえず不効率版。後ほど書き直し予定
  126. void graph_square(struct graph* g,int x,int y,int xe,int ye,int color) {
  127. int i,j;
  128. if(g == NULL) return;
  129. if(x < 0) { x = 0; }
  130. if(y < 0) { y = 0; }
  131. if(xe > g->width) { xe = g->width; }
  132. if(ye > g->height) { ye = g->height; }
  133. for(i = y;i < ye ; i++) {
  134. for(j = x; j < xe ; j++) {
  135. graph_setpixel(g,j,i,color);
  136. }
  137. }
  138. }
  139. // とりあえず不効率版。後ほど書き直し予定
  140. void graph_scroll(struct graph* g,int n,int color) {
  141. int x,y;
  142. if(g == NULL) return;
  143. for(y = 0; y < g->height; y++) {
  144. for(x = 0; x < g->width - n; x++) {
  145. graph_setpixel(g,x,y,graph_getpixel(g,x + n,y));
  146. }
  147. for( ; x < g->width; x++) {
  148. graph_setpixel(g,x,y,color);
  149. }
  150. }
  151. }
  152. void graph_data(struct graph* g,int value) {
  153. int i, j, start;
  154. if(g == NULL) return;
  155. memmove(&g->graph_value[0],&g->graph_value[1],sizeof(int) * (g->width - 1));
  156. g->graph_value[g->width - 1] = value;
  157. if(value > g->graph_max) {
  158. // 最大値を超えたので再描画
  159. g->graph_max = value;
  160. graph_square(g,0,0,g->width,g->height,0);
  161. start = 0;
  162. } else {
  163. // スクロールしてポイント打つ
  164. graph_scroll(g,1,0);
  165. start = g->width - 1;
  166. }
  167. for(i = start; i < g->width; i++) {
  168. int h0 = (i == 0 ? 0 : g->graph_value[i - 1]) * g->height / g->graph_max;
  169. int h1 = (g->graph_value[i] ) * g->height / g->graph_max;
  170. int h2 = (h0 < h1 ? 1 : -1);
  171. for(j = h0; j != h1; j += h2) {
  172. graph_setpixel(g,i,g->height - 1 - j,1);
  173. }
  174. graph_setpixel(g,i,g->height - 1 - h1,1);
  175. }
  176. }
  177. // 上の関数群を利用して、自動的にグラフを作成するタイマー群
  178. #define GRP_WIDTH 300 // グラフの幅
  179. #define GRP_HEIGHT 200 // グラフの高さ
  180. #define GRP_COLOR graph_rgb(0,0,255) // グラフの色
  181. #define GRP_INTERVEL 60*1000 // グラフの更新間隔
  182. #define GRP_PATH "httpd/"
  183. struct graph_sensor {
  184. struct graph* graph;
  185. char* str;
  186. char hash[32];
  187. int scanid;
  188. int drawid;
  189. int interval;
  190. unsigned int (*func)(void);
  191. };
  192. static struct graph_sensor *sensor;
  193. static int sensor_max;
  194. static int graph_scan_timer(int tid,unsigned int tick,int id,int data)
  195. {
  196. if(id >= 0 && id < sensor_max)
  197. graph_data(sensor[id].graph,sensor[id].func());
  198. return 0;
  199. }
  200. // modified by Celest -- i'm trying to separate it from httpd if possible ^^;
  201. static int graph_draw_timer(int tid,unsigned int tick,int id,int data)
  202. {
  203. char png_file[24];
  204. FILE *fp;
  205. // create/update the png file
  206. do {
  207. const char *png_data;
  208. int len;
  209. sprintf (png_file, GRP_PATH"%s.png", sensor[id].hash);
  210. fp = fopen(png_file, "w");
  211. // if another png of the same hash exists
  212. // (i.e 2nd login server with the same sensors)
  213. // this will fail = not good >.<
  214. if (fp == NULL)
  215. break;
  216. png_data = graph_output(sensor[id].graph, &len);
  217. fwrite(png_data,1,len,fp);
  218. fclose(fp);
  219. } while (0);
  220. // create/update text snippet
  221. do {
  222. char buf[8192], *p;
  223. p = buf;
  224. sprintf (png_file, GRP_PATH"%s.graph", sensor[id].hash);
  225. fp = fopen(png_file, "w");
  226. if (fp == NULL)
  227. break;
  228. p += sprintf(p,"<h2>%s</h2>\n\n",
  229. sensor[id].str);
  230. p += sprintf(p,"<p><img src=\"%s.png\" width=\"%d\" height=\"%d\"></p>\n",
  231. sensor[id].hash, GRP_WIDTH,GRP_HEIGHT);
  232. p += sprintf(p,"<p>Max: %d, Interval: %d sec</p>\n\n",
  233. sensor[id].graph->graph_max, sensor[id].interval / 1000);
  234. fprintf(fp, buf);
  235. fclose(fp);
  236. } while (0);
  237. return 0;
  238. }
  239. void graph_add_sensor(const char* string, int interval, unsigned int (*callback_func)(void))
  240. {
  241. int draw_interval = interval * 2;
  242. struct graph *g = graph_create(GRP_WIDTH,GRP_HEIGHT);
  243. graph_pallet(g,1,GRP_COLOR);
  244. sensor = (struct graph_sensor *) aRealloc(sensor, sizeof(struct graph_sensor) * (sensor_max + 1));
  245. sensor[sensor_max].graph = g;
  246. sensor[sensor_max].str = aStrdup(string);
  247. // create crc32 hash of the sensor's name
  248. sprintf (sensor[sensor_max].hash, "%lu%c", grfio_crc32(string,strlen(string)), 'a' + SERVER_TYPE);
  249. sensor[sensor_max].func = callback_func;
  250. sensor[sensor_max].scanid = add_timer_interval(gettick() + 500, graph_scan_timer, sensor_max, 0, interval);
  251. sensor[sensor_max].drawid = add_timer_interval(gettick() + 1000, graph_draw_timer, sensor_max, 0, draw_interval < 60000 ? 60000 : draw_interval);
  252. sensor[sensor_max].interval = interval;
  253. sensor_max++;
  254. }
  255. void graph_final (void)
  256. {
  257. int i;
  258. for(i = 0; i < sensor_max; i++) {
  259. char png_file[24];
  260. // remove the png and snippet file
  261. sprintf (png_file, GRP_PATH"%s.png", sensor[i].hash);
  262. unlink (png_file);
  263. sprintf (png_file, GRP_PATH"%s.graph", sensor[i].hash);
  264. unlink (png_file);
  265. graph_free(sensor[i].graph);
  266. aFree(sensor[i].str);
  267. //delete_timer(sensor[i].scanid,graph_scan_timer);
  268. //delete_timer(sensor[i].drawid,graph_draw_timer);
  269. }
  270. aFree(sensor);
  271. sensor_max = 0;
  272. }
  273. void graph_init (void)
  274. {
  275. graph_add_sensor ("Memory Usage", 1000, malloc_usage);
  276. add_timer_func_list(graph_scan_timer, "graph_scan_timer");
  277. add_timer_func_list(graph_draw_timer, "graph_draw_timer");
  278. }
  279. #else
  280. void graph_init (void) {}
  281. void graph_final (void) {}
  282. #endif