1/*
2 * merge.c:  Program to take mutiple strand format logfiles, sort them,
3 *           merge them, and prepend information to the final logfile.
4 *
5 * Algorithm:
6 *     Copy all the negative events at the beginning of the logfiles to a
7 *       temporary header file.
8 *     Use the unix sort command to sort all the logfiles.
9 *     Analyze the data, ignoring all events that are not > 0.
10 *     Print to stdout the results of the analyzation, the header file,
11 *       and the sorted log entries.
12 *
13 *	Modified Summer 1990 by James Arthur Kohl
14 *		to combine count collection more efficiently.
15 *
16 *		Now it's REAL fast!
17 */
18#include <stdio.h>
19#include <stdlib.h>
20#include <malloc.h>
21#include <ctype.h>           /* for calling isdigit()             */
22#include "alog_evntdfs.h"       /* Logfile definitions */
23
24#define C_DATA_LEN 50
25
26#define DO_NEGATIVE 1
27#define IGNORE_NEGATIVE 2
28
29struct log_entry
30{
31	int proc_id;
32	int task_id;
33	int event;
34	int i_data;
35	char c_data[C_DATA_LEN];
36	int time_slot;
37	unsigned long time;
38};
39
40struct list_struct
41{
42	struct log_entry entry;
43	struct list_struct *next;
44} *log_table;
45
46struct list_struct *log_ptr;
47
48int entry_tot;
49
50main(argc,argv)
51int argc;
52char *argv[];
53{
54	FILE *headerfp;
55
56	char headerfile[255];
57
58	int pid;
59
60	if ( argc <= 1 )
61		usage();
62
63	pid = getpid();
64
65	sprintf(headerfile,"/usr/tmp/log.header.%d",pid);
66
67	if ( (headerfp=fopen(headerfile,"w")) == NULL )
68	{
69		fprintf(stderr,"merge: unable to create temp file %s.\n",headerfile);
70		exit(0);
71	}
72
73	combine_files(argc,argv,headerfp);
74
75	if ( (headerfp=fopen(headerfile,"r")) == NULL )
76	{
77		fprintf(stderr,"merge: unable to read temp file %s.\n",headerfile);
78		exit(0);
79	}
80
81	fprintf(stderr,"Analyzing.\n");
82	analyze(headerfp);
83
84	fclose(headerfp);
85	unlink(headerfile);
86} /* main */
87
88
89combine_files(argc,argv,headerfp)
90int argc;
91char *argv[];
92FILE *headerfp;
93{
94	FILE *in;
95
96	struct list_struct **files;
97	struct list_struct *last;
98	struct list_struct *ptr;
99
100	struct log_entry *entry;
101
102	unsigned long min_time;
103
104	int min_event;
105	int min_slot;
106	int min;
107
108	int all_eof;
109	int eof_flag;
110	int negflag;
111	int num;
112	int i;
113
114	num = argc - 1;
115
116	if ( (files=(struct list_struct **)
117		malloc(num * sizeof(struct list_struct *))) == NULL )
118	{
119		fprintf(stderr,"merge: unable to allocate input data array.\n");
120		exit(0);
121	}
122
123	for ( i=0 ; i < num ; i++ )
124	{
125		fprintf(stderr,"Reading %s\n",argv[i+1]);
126
127		if ( (in=fopen(argv[i+1],"r")) == NULL )
128		{
129			fprintf(stderr,"merge: unable to read data file %s.\n",argv[i+1]);
130			exit(0);
131		}
132
133		if ( (files[i]=(struct list_struct *)
134			malloc(sizeof(struct list_struct))) == NULL )
135		{
136			fprintf(stderr,"merge: unable to allocate list struct.\n");
137			exit(0);
138		}
139
140		ptr = files[i];
141
142		last = NULL;
143
144		do
145		{
146			read_logentry(in,&(ptr->entry),DO_NEGATIVE);
147
148			if ( !(eof_flag=feof(in)) )
149			{
150				if ( (ptr->next=(struct list_struct *)
151					malloc(sizeof(struct list_struct))) == NULL )
152				{
153					fprintf(stderr,"merge: unable to allocate list struct.\n");
154					exit(0);
155				}
156
157				last = ptr;
158
159				ptr = ptr->next;
160			}
161
162			else
163			{
164				if ( last != NULL )
165					last->next = NULL;
166
167				else
168					files[i] = NULL;
169
170				free(ptr);
171				ptr = NULL;
172			}
173		}
174		while ( !eof_flag );
175
176		fclose(in);
177	}
178
179	fprintf(stderr,"Sorting.\n");
180
181	all_eof = 0;
182
183	do
184	{
185		negflag = 0;
186
187		for ( i=0 ; i < num ; i++ )
188		{
189			if ( files[i] == NULL )
190				continue;
191
192			entry = &(files[i]->entry);
193
194			if ( entry->event < 0 )
195			{
196				negflag++;
197
198				fprintf(headerfp,"%d %d %d %d %d %lu %s\n",entry->event,
199					entry->proc_id,entry->task_id,entry->i_data,
200					entry->time_slot,entry->time,entry->c_data);
201
202				files[i] = files[i]->next;
203
204				if ( files[i] == NULL )
205					all_eof++;
206			}
207		}
208	}
209	while ( negflag && all_eof < num );
210
211	fclose(headerfp);
212
213	log_table = log_ptr = NULL;
214
215	entry_tot = 0;
216
217	while ( all_eof < num )
218	{
219		min_event = 0;
220		min_time = 0;
221		min_slot = 0;
222
223		min = -1;
224
225		for ( i=0 ; i < num ; i++ )
226		{
227			if ( files[i] == NULL )
228				continue;
229
230			entry = &(files[i]->entry);
231
232			if (
233				(entry->time_slot == min_slot && entry->time < min_time)
234				|| entry->time_slot < min_slot
235				|| min == -1
236				|| (entry->time_slot == min_slot && entry->time == min_time
237					&& entry->event < min_event)
238				)
239			{
240				min_event = entry->event;
241				min_time = entry->time;
242				min_slot = entry->time_slot;
243
244				min = i;
245			}
246		}
247
248		if ( log_ptr == NULL )
249		{
250			log_table = log_ptr = files[min];
251
252			files[min] = files[min]->next;
253		}
254
255		else
256		{
257			log_ptr->next = files[min];
258
259			files[min] = files[min]->next;
260
261			log_ptr = log_ptr->next;
262		}
263
264		log_ptr->next = NULL;
265
266		entry_tot++;
267
268		if ( files[min] == NULL )
269			all_eof++;
270	}
271
272	fprintf(stderr, "  %d total entries\n", entry_tot);
273}
274
275
276usage()
277{
278	fprintf(stderr,"mergelogs: mergelogs infile1 infile2 ...\n");
279	fprintf(stderr,"  writes to stdout\n");
280
281	exit(0);
282}
283
284
285/* analyze:  At this point, we have one large sorted file called :tname:.
286 *           We want to prepend certain data to it.
287 *           We also want to prepend the data from the file pointed to
288 *             by :headerfp:.
289 *           See balance:/usr/local/trace/README for info.
290 *
291 */
292analyze(headerfp)
293FILE *headerfp;
294{
295	struct log_entry *entry;
296
297	int proc_tot, task_tot, time_slot_tot, event_tot;
298	int i;
299
300	get_counts(&proc_tot,&task_tot,&event_tot,&time_slot_tot);
301
302	fprintf(stderr, "  %d separate processors\n",  proc_tot);
303	fprintf(stderr, "  %d separate tasks\n",  task_tot);
304	fprintf(stderr, "  %d event types\n", event_tot);
305
306	fprintf(stdout,"%d %d %d %d %d %lu\n",NUM_EVENTS,0,0,entry_tot,0,0L);
307	fprintf(stdout,"%d %d %d %d %d %lu\n",NUM_PROCS,0,0,proc_tot,0,0L);
308	fprintf(stdout,"%d %d %d %d %d %lu\n",NUM_TASKS,0,0,task_tot,0,0L);
309	fprintf(stdout,"%d %d %d %d %d %lu\n",NUM_EVTYPES,0,0,event_tot,0,0L);
310	fprintf(stdout,"%d %d %d %d %d %lu\n",START_TIME,0,0,0,0,
311		log_table->entry.time);
312	fprintf(stdout,"%d %d %d %d %d %lu\n",END_TIME,0,0,0,0,
313		log_ptr->entry.time);
314	fprintf(stdout,"%d %d %d %d %d %lu\n",NUM_CYCLES,0,0,time_slot_tot,0,0L);
315
316	dump_header(headerfp);
317
318	log_ptr = log_table;
319
320	while ( log_ptr != NULL )
321	{
322		entry = &(log_ptr->entry);
323
324		fprintf(stdout,"%d %d %d %d %d %lu  %s\n",entry->event,
325			entry->proc_id,entry->task_id,entry->i_data,
326			entry->time_slot,entry->time,entry->c_data);
327
328		log_ptr = log_ptr->next;
329	}
330} /* analyze */
331
332
333dump_header(headerfp)
334FILE *headerfp;
335{
336	char buf[512];
337	int len;
338
339	do
340	{
341		if ( len=fread(buf,sizeof(char),512,headerfp) )
342			fwrite(buf,sizeof(char),len,stdout);
343	}
344	while ( !feof(headerfp) && len );
345} /* dump_header */
346
347
348read_logentry(fp,table,do_negs)
349FILE *fp;
350struct log_entry *table;
351int do_negs;
352{
353	char buf[81];
354	char *cp;
355
356	int i;
357
358	do
359	{
360		fscanf(fp,"%d %d %d %d %d %lu",
361			&(table->event),&(table->proc_id),&(table->task_id),
362			&(table->i_data),&(table->time_slot),&(table->time));
363
364		cp = table->c_data;
365
366		i = 0;
367
368		do
369		{
370			fscanf(fp,"%c",cp);
371		}
372		while ( *cp == ' ' || *cp == '\t' );
373
374		i++;
375
376		while ( *cp != '\n' && i < C_DATA_LEN )
377		{
378			fscanf(fp,"%c",++cp);
379
380			i++;
381		}
382
383		*cp = '\0';
384
385		/*
386		if ( !feof(fp) && table->event == 0 )
387			fprintf(stderr,"0 reading in.\n");
388		*/
389	}
390	while( table->event < 0 && do_negs == IGNORE_NEGATIVE && !feof(fp) );
391}
392
393
394get_counts(ptot,ttot,etot,tstot)
395int *ptot,*ttot,*etot,*tstot;
396{
397	struct list_struct *ptr;
398
399	struct log_entry *entry;
400	struct log_entry *last;
401
402	int *p, *t, *e;
403
404	int flag;
405	int val;
406	int i,j;
407
408	if ( (p=(int *)malloc(sizeof(int) * entry_tot)) == NULL )
409	{
410		fprintf(stderr,"Not enough memory.\n");
411		exit(0);
412	}
413
414	if ( (t=(int *)malloc(sizeof(int) * entry_tot)) == NULL )
415	{
416		fprintf(stderr,"Not enough memory.\n");
417		exit(0);
418	}
419
420	if ( (e=(int *)malloc(sizeof(int) * entry_tot)) == NULL )
421	{
422		fprintf(stderr,"Not enough memory.\n");
423		exit(0);
424	}
425
426	for ( i=0 ; i < entry_tot ; i++ )
427	{
428		p[i] = t[i] = e[i] = 0;
429	}
430
431	*ptot = *ttot = *etot = 0;
432
433	*tstot = 1;
434
435	ptr = log_table;
436
437	last = NULL;
438
439	while ( ptr != NULL )
440	{
441		entry = &(ptr->entry);
442
443		flag = 0;
444
445		val = entry->proc_id;
446
447		for ( j=0 ; j < *ptot && !flag ; j++ )
448		{
449			if ( p[j] == val )
450				flag++;
451		}
452
453		if ( !flag )
454		{
455			p[(*ptot)++] = val;
456		}
457
458		flag = 0;
459
460		val = entry->task_id;
461
462		for ( j=0 ; j < *ttot && !flag ; j++ )
463		{
464			if ( t[j] == val )
465				flag++;
466		}
467
468		if ( !flag )
469		{
470			t[(*ttot)++] = val;
471		}
472
473		flag = 0;
474
475		val = entry->event;
476
477		for ( j=0 ; j < *etot && !flag ; j++ )
478		{
479			if ( e[j] == val )
480				flag++;
481		}
482
483		if ( !flag )
484		{
485			e[(*etot)++] = val;
486		}
487
488                /* printf("tstot=%d *tstot=%d\n",tstot,*tstot); */
489		if ( (last != NULL) && (entry->time_slot != last->time_slot) )
490                        *tstot = *tstot + 1;
491			/*  (*tstot)++;  */
492
493		last = entry;
494
495		ptr = ptr->next;
496	}
497        return(0);
498}
499