litl  0.1.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
litl_merge.c
Go to the documentation of this file.
1 /* -*- c-file-style: "GNU" -*- */
2 /*
3  * Copyright © Télécom SudParis.
4  * See COPYING in top-level directory.
5  */
6 
7 #define _GNU_SOURCE
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/stat.h>
13 
14 #include "litl_merge.h"
15 
16 static litl_trace_merge_t* __arch;
17 static litl_trace_triples_t** __triples;
18 
19 /*
20  * Sets a new name for the archive
21  */
22 static void __litl_merge_set_archive_name(const char* filename) {
23  int res __attribute__ ((__unused__));
24 
25  // check whether the file name was set. If no, set it by default trace name
26  if (filename == NULL )
27  res = asprintf(&__arch->filename, "/tmp/%s_%s", getenv("USER"),
28  "litl_archive_1");
29 
30  if (asprintf(&__arch->filename, "%s", filename) == -1) {
31  perror("Error: Cannot set the filename for recording events!\n");
32  exit(EXIT_FAILURE);
33  }
34 }
35 
36 /*
37  * Adds a trace header:
38  * - The number of traces
39  * - Triples: a file id, a file size, and an offset
40  */
41 static void __litl_merge_add_archive_header() {
42 
43  int trace_in, res __attribute__ ((__unused__));
44  litl_med_size_t trace_index, process_index, general_header_size,
45  process_header_size, global_header_size, nb_processes, total_nb_processes;
46  litl_buffer_t header_buffer;
47 
48  total_nb_processes = 0;
49  global_header_size = 0;
50  general_header_size = sizeof(litl_general_header_t);
51  process_header_size = sizeof(litl_process_header_t);
52 
53  // create an array of arrays of offsets
54  __triples = (litl_trace_triples_t **) malloc(
55  __arch->nb_traces * sizeof(litl_trace_triples_t *));
56 
57  // read all header of traces and write them to the global header of the archive
58  for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++) {
59 
60  if ((trace_in = open(__arch->traces_names[trace_index], O_RDONLY)) < 0) {
61  fprintf(stderr, "[litl_merge] Cannot open %s to read its header\n",
62  __arch->traces_names[trace_index]);
63  exit(EXIT_FAILURE);
64  }
65 
66  // read the trace header
67  header_buffer = (litl_buffer_t) malloc(general_header_size);
68  res = read(trace_in, header_buffer, general_header_size);
69 
70  nb_processes = ((litl_general_header_t *) header_buffer)->nb_processes;
71  __triples[trace_index] = (litl_trace_triples_t *) malloc(
72  nb_processes * sizeof(litl_trace_triples_t));
73 
74  // add a general header
75  if (trace_index == 0) {
76  sprintf((char*) ((litl_general_header_t *) __arch->buffer)->litl_ver,
77  "%s",
78  (char*) ((litl_general_header_t *) header_buffer)->litl_ver);
79  sprintf((char*) ((litl_general_header_t *) __arch->buffer)->sysinfo, "%s",
80  (char*) ((litl_general_header_t *) header_buffer)->sysinfo);
81 
82  global_header_size += general_header_size;
83  __arch->buffer += general_header_size;
84  }
85 
86  // read headers of processes
87  res = read(trace_in, __arch->buffer, nb_processes * process_header_size);
88 
89  // find the trace size
90  if (nb_processes == 1) {
91  struct stat st;
92  if (fstat(trace_in, &st)) {
93  perror("Cannot apply fstat to the input trace files!");
94  exit(EXIT_FAILURE);
95  }
96 
97  ((litl_process_header_t *) __arch->buffer)->trace_size =
98  (litl_trace_size_t) st.st_size - general_header_size
99  - process_header_size;
100  }
101 
102  for (process_index = 0; process_index < nb_processes; process_index++) {
103  __triples[trace_index][process_index].nb_processes = nb_processes;
104  __triples[trace_index][process_index].position = global_header_size
105  + (process_index + 1) * process_header_size - sizeof(litl_offset_t);
106  __triples[trace_index][process_index].offset =
107  ((litl_process_header_t *) __arch->buffer)->offset - general_header_size
108  - nb_processes * process_header_size;
109  __arch->buffer += process_header_size;
110  }
111 
112  total_nb_processes += nb_processes;
113  global_header_size += nb_processes * process_header_size;
114 
115  free(header_buffer);
116  close(trace_in);
117  }
118 
119  // update the number of processes
120  ((litl_general_header_t *) __arch->buffer_ptr)->nb_processes =
121  total_nb_processes;
122 
123  res = write(__arch->f_handle, __arch->buffer_ptr, global_header_size);
124  __arch->general_offset += global_header_size;
125  __arch->buffer = __arch->buffer_ptr;
126 }
127 
128 /*
129  * Creates and opens an archive for traces.
130  * Allocates memory for the buffer
131  */
132 static void __litl_merge_init_archive(const char* arch_name,
133  char** traces_names, const int nb_traces) {
134 
135  __arch = (litl_trace_merge_t *) malloc(sizeof(litl_trace_merge_t));
136 
137  // allocate buffer for read/write ops
138  __arch->buffer_size = 16 * 1024 * 1024; // 16 MB
139  __arch->buffer_ptr = (litl_buffer_t) calloc(__arch->buffer_size, 1);
140  __arch->buffer = __arch->buffer_ptr;
141 
142  __arch->nb_traces = nb_traces;
143  __arch->traces_names = traces_names;
144  __arch->general_offset = 0;
145 
146  __litl_merge_set_archive_name(arch_name);
147 
148  // create an archive for trace files in rw-r-r- mode (0644)
149  if ((__arch->f_handle = open(__arch->filename, O_WRONLY | O_CREAT, 0644))
150  < 0) {
151  fprintf(stderr, "[litl_merge] Cannot open %s archive\n", __arch->filename);
152  exit(EXIT_FAILURE);
153  }
154 
155  // add a general archive header and also a set of process headers
156  __litl_merge_add_archive_header();
157 }
158 
159 /*
160  * Merges trace files. This is a modified version of the cat implementation
161  * from the Kernighan & Ritchie book
162  */
163 static void __litl_merge_create_archive() {
164  int trace_in, res;
166  litl_med_size_t trace_index, process_index, nb_processes;
167  litl_trace_size_t header_offset, general_header_size, process_header_size;
168 
169  general_header_size = sizeof(litl_general_header_t);
170  process_header_size = sizeof(litl_process_header_t);
171 
172  for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++) {
173  if ((trace_in = open(__arch->traces_names[trace_index], O_RDONLY)) < 0) {
174  fprintf(stderr, "[litl_merge] Cannot open %s\n",
175  __arch->traces_names[trace_index]);
176  exit(EXIT_FAILURE);
177  }
178 
179  // update offsets of processes
180  nb_processes = __triples[trace_index][0].nb_processes;
181  for (process_index = 0; process_index < nb_processes; process_index++) {
182  lseek(__arch->f_handle, __triples[trace_index][process_index].position,
183  SEEK_SET);
184  offset = __triples[trace_index][process_index].offset
185  + __arch->general_offset;
186  res = write(__arch->f_handle, &offset, sizeof(litl_offset_t));
187  lseek(__arch->f_handle, __arch->general_offset, SEEK_SET);
188  }
189 
190  // merge traces
191  header_offset = general_header_size + nb_processes * process_header_size;
192  lseek(trace_in, header_offset, SEEK_SET);
193 
194  // solution: Reading and writing blocks of data. Use the file size
195  // to deal with the reading of the last block from the
196  // traces
197  while (1) {
198  res = read(trace_in, __arch->buffer, __arch->buffer_size);
199 
200  if (res < 0) {
201  perror("Cannot read the data from the traces!");
202  exit(EXIT_FAILURE);
203  }
204 
205  res = write(__arch->f_handle, __arch->buffer, res);
206  __arch->general_offset += res;
207 
208  if ((litl_size_t) res < __arch->buffer_size)
209  break;
210  }
211 
212  close(trace_in);
213  }
214 }
215 
216 /*
217  * Frees the allocated memory
218  */
219 static void __litl_merge_finalize_archive() {
220  close(__arch->f_handle);
221 
222  // free offsets
223  litl_med_size_t trace_index;
224  for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++)
225  free(__triples[trace_index]);
226  free(__triples);
227 
228  // free filenames
229  free(__arch->filename);
230  for (trace_index = 0; trace_index < __arch->nb_traces; trace_index++)
231  free(__arch->traces_names[trace_index]);
232  free(__arch->traces_names);
233 
234  free(__arch->buffer_ptr);
235 
236  __arch->buffer_ptr = NULL;
237  __arch = NULL;
238 }
239 
240 void litl_merge_traces(const char* arch_name, char** traces_names,
241  const int nb_traces) {
242  __litl_merge_init_archive(arch_name, traces_names, nb_traces);
243 
244  __litl_merge_create_archive();
245 
246  __litl_merge_finalize_archive();
247 }
litl_size_t buffer_size
Definition: litl_types.h:408
void litl_merge_traces(const char *arch_name, char **traces_names, const int nb_traces)
Merges trace files into an archive. This is a modified version of the implementation of the cat funct...
Definition: litl_merge.c:240
litl_med_size_t nb_processes
Definition: litl_types.h:281
litl_merge Provides a set of functions for merging trace files into an archive of traces ...
litl_offset_t offset
Definition: litl_types.h:283
A general data structure that corresponds to the header of a trace file.
Definition: litl_types.h:258
litl_med_size_t nb_traces
Definition: litl_types.h:403
uint8_t * litl_buffer_t
A data type for storing sets of events.
Definition: litl_types.h:133
litl_buffer_t buffer
Definition: litl_types.h:407
uint16_t litl_med_size_t
An auxiliary data type for the optimized storage of data.
Definition: litl_types.h:150
An offset event.
A data structure for merging trace files into an archive of traces.
Definition: litl_types.h:399
litl_offset_t general_offset
Definition: litl_types.h:410
uint32_t litl_size_t
An auxiliary data type for storing data.
Definition: litl_types.h:145
uint64_t litl_trace_size_t
A data type for storing traces sizes.
Definition: litl_types.h:117
uint64_t litl_offset_t
A data type for storing offsets.
Definition: litl_types.h:127
A general data structure that corresponds to the header of a trace file.
Definition: litl_types.h:247
litl_offset_t position
Definition: litl_types.h:282
A data structure for triples (nb_processes, position, offset)
Definition: litl_types.h:280
litl_buffer_t buffer_ptr
Definition: litl_types.h:406
char ** traces_names
Definition: litl_types.h:404