litl 0.1.9
Loading...
Searching...
No Matches
src/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
16static litl_trace_merge_t* __arch;
17static litl_trace_triples_t** __triples;
18
19/*
20 * Sets a new name for the archive
21 */
22static 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 */
41static 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
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 */
132static 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 */
163static 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 */
219static 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
240void 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}
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...
uint32_t litl_size_t
An auxiliary data type for storing data.
Definition litl_types.h:147
uint8_t * litl_buffer_t
A data type for storing sets of events.
Definition litl_types.h:135
uint16_t litl_med_size_t
An auxiliary data type for the optimized storage of data.
Definition litl_types.h:152
uint64_t litl_trace_size_t
A data type for storing traces sizes.
Definition litl_types.h:119
uint64_t litl_offset_t
A data type for storing offsets.
Definition litl_types.h:129
litl_merge Provides a set of functions for merging trace files into an archive of traces
A general data structure that corresponds to the header of a trace file.
Definition litl_types.h:249
A general data structure that corresponds to the header of a trace file.
Definition litl_types.h:260
A data structure for merging trace files into an archive of traces.
Definition litl_types.h:402
litl_size_t buffer_size
Definition litl_types.h:411
litl_med_size_t nb_traces
Definition litl_types.h:406
litl_offset_t general_offset
Definition litl_types.h:413
litl_buffer_t buffer_ptr
Definition litl_types.h:409
litl_buffer_t buffer
Definition litl_types.h:410
A data structure for triples (nb_processes, position, offset)
Definition litl_types.h:282
litl_offset_t position
Definition litl_types.h:284
litl_offset_t offset
Definition litl_types.h:285
litl_med_size_t nb_processes
Definition litl_types.h:283
An offset event.