Home | History | Annotate | Download | only in ioshark
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <fcntl.h>
     18 #include <stdio.h>
     19 #include <sys/types.h>
     20 #include <unistd.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <sys/stat.h>
     24 #include <sys/errno.h>
     25 #include "ioshark.h"
     26 #include "compile_ioshark.h"
     27 #include <endian.h>
     28 
     29 extern char *progname;
     30 
     31 static struct files_db_s *files_db_buckets[FILE_DB_HASHSIZE];
     32 static int current_fileno = 1;
     33 static int num_objects = 0;
     34 
     35 static int filename_cache_lookup(char *filename);;
     36 
     37 void
     38 files_db_write_objects(FILE *fp)
     39 {
     40 	int i;
     41 	struct ioshark_file_state st;
     42 
     43 	for (i = 0 ; i < FILE_DB_HASHSIZE ; i++) {
     44 		struct files_db_s *db_node, *s;
     45 
     46 		db_node = files_db_buckets[i];
     47 		while (db_node != NULL) {
     48 			st.fileno = db_node->fileno;
     49 			st.size = db_node->size;
     50 			st.global_filename_ix =
     51 				db_node->global_filename_ix;
     52 			if (ioshark_write_file_state(fp, &st) != 1) {
     53 				fprintf(stderr,
     54 					"%s Write error trace.outfile\n",
     55 					progname);
     56 				exit(EXIT_FAILURE);
     57 			}
     58 			s = db_node;
     59 			db_node = db_node->next;
     60 			free(s->filename);
     61 			free(s);
     62 		}
     63 	}
     64 }
     65 
     66 void *files_db_lookup(char *pathname)
     67 {
     68 	u_int32_t hash;
     69 	struct files_db_s *db_node;
     70 
     71 	hash = jenkins_one_at_a_time_hash(pathname, strlen(pathname));
     72 	hash %= FILE_DB_HASHSIZE;
     73 	db_node = files_db_buckets[hash];
     74 	while (db_node != NULL) {
     75 		if (strcmp(db_node->filename, pathname) == 0)
     76 			break;
     77 		db_node = db_node->next;
     78 	}
     79 	return db_node;
     80 }
     81 
     82 void *files_db_add(char *filename)
     83 {
     84 	u_int32_t hash;
     85 	struct files_db_s *db_node;
     86 
     87 	if ((db_node = files_db_lookup(filename)))
     88 		return db_node;
     89 	hash = jenkins_one_at_a_time_hash(filename, strlen(filename));
     90 	hash %= FILE_DB_HASHSIZE;
     91 	db_node = malloc(sizeof(struct files_db_s));
     92 	db_node->filename = strdup(filename);
     93 	db_node->global_filename_ix =
     94 		filename_cache_lookup(filename);
     95 	db_node->fileno = current_fileno++;
     96 	db_node->next = files_db_buckets[hash];
     97 	db_node->size = 0;
     98 	files_db_buckets[hash] = db_node;
     99 	num_objects++;
    100 	return db_node;
    101 }
    102 
    103 int
    104 files_db_get_total_obj(void)
    105 {
    106 	return num_objects;
    107 }
    108 
    109 static struct ioshark_filename_struct *filename_cache;
    110 static int filename_cache_num_entries;
    111 static int filename_cache_size;
    112 
    113 void
    114 init_filename_cache(void)
    115 {
    116 	static FILE *filename_cache_fp;
    117 	struct stat st;
    118 	int file_exists = 1;
    119 
    120 	if (stat("ioshark_filenames", &st) < 0) {
    121 		if (errno != ENOENT) {
    122 			fprintf(stderr, "%s Can't stat ioshark_filenames file\n",
    123 				progname);
    124 			exit(EXIT_FAILURE);
    125 		} else {
    126 			file_exists = 0;
    127 			filename_cache_num_entries = 0;
    128 		}
    129 	} else {
    130 		filename_cache_num_entries = st.st_size /
    131 			sizeof(struct ioshark_filename_struct);
    132 	}
    133 	if (file_exists) {
    134 		filename_cache_fp = fopen("ioshark_filenames", "r");
    135 		if (filename_cache_fp == NULL) {
    136 			fprintf(stderr, "%s Cannot open ioshark_filenames file\n",
    137 				progname);
    138 			exit(EXIT_FAILURE);
    139 		}
    140 	}
    141 	/* Preallocate a fixed size of entries */
    142 	filename_cache_size = filename_cache_num_entries + 1024;
    143 	filename_cache = calloc(filename_cache_size,
    144 				sizeof(struct ioshark_filename_struct));
    145 	if (filename_cache == NULL) {
    146 		fprintf(stderr, "%s Can't allocate memory - this is fatal\n",
    147 			__func__);
    148 		exit(EXIT_FAILURE);
    149 	}
    150 	if (fread(filename_cache,
    151 		  sizeof(struct ioshark_filename_struct),
    152 		  filename_cache_num_entries,
    153 		  filename_cache_fp) != (size_t)filename_cache_num_entries) {
    154 		fprintf(stderr, "%s Can't read ioshark_filenames file\n",
    155 			progname);
    156 		exit(EXIT_FAILURE);
    157 	}
    158 	if (file_exists)
    159 		fclose(filename_cache_fp);
    160 }
    161 
    162 static int
    163 filename_cache_lookup(char *filename)
    164 {
    165 	int ret;
    166 	int i;
    167 
    168 	for (i = 0 ; i < filename_cache_num_entries ; i++) {
    169 		if (strcmp(filename_cache[i].path, filename) == 0)
    170 			return i;
    171 	}
    172 	if (filename_cache_num_entries >= filename_cache_size) {
    173 		int newsize;
    174 
    175 		/* reallocate the filename cache up first */
    176 		filename_cache_size += 1024;
    177 		newsize = filename_cache_size *
    178 			sizeof(struct ioshark_filename_struct);
    179 		filename_cache = realloc(filename_cache, newsize);
    180 		if (filename_cache == NULL) {
    181 			fprintf(stderr,
    182 				"%s Can't allocate memory - this is fatal\n",
    183 				__func__);
    184 			exit(EXIT_FAILURE);
    185 		}
    186 	}
    187 	strcpy(filename_cache[filename_cache_num_entries].path,
    188 	       filename);
    189 	ret = filename_cache_num_entries;
    190 	filename_cache_num_entries++;
    191 	return ret;
    192 }
    193 
    194 void
    195 store_filename_cache(void)
    196 {
    197 	static FILE *filename_cache_fp;
    198 
    199 	filename_cache_fp = fopen("ioshark_filenames", "w+");
    200 	if (filename_cache_fp == NULL) {
    201 		fprintf(stderr, "%s Cannot open ioshark_filenames file\n",
    202 			progname);
    203 		exit(EXIT_FAILURE);
    204 	}
    205 	if (fwrite(filename_cache,
    206 		   sizeof(struct ioshark_filename_struct),
    207 		   filename_cache_num_entries,
    208 		   filename_cache_fp) != (size_t)filename_cache_num_entries) {
    209 		fprintf(stderr, "%s Can't read ioshark_filenames file\n",
    210 			progname);
    211 		exit(EXIT_FAILURE);
    212 	}
    213 	fclose(filename_cache_fp);
    214 	free(filename_cache);
    215 }
    216 
    217 int
    218 ioshark_write_header(FILE *fp, struct ioshark_header *header)
    219 {
    220 	header->version = htobe64(header->version);
    221 	header->num_files = htobe64(header->num_files);
    222 	header->num_io_operations = htobe64(header->num_io_operations);
    223 	return fwrite(header, sizeof(struct ioshark_header), 1, fp);
    224 }
    225 
    226 int
    227 ioshark_write_file_state(FILE *fp, struct ioshark_file_state *state)
    228 {
    229 	state->fileno = htobe64(state->fileno);
    230 	state->size = htobe64(state->size);
    231 	state->global_filename_ix = htobe64(state->global_filename_ix);
    232 	return fwrite(state, sizeof(struct ioshark_file_state), 1, fp);
    233 }
    234 
    235 int
    236 ioshark_write_file_op(FILE *fp, struct ioshark_file_operation *file_op)
    237 {
    238 	enum file_op op = file_op->ioshark_io_op;
    239 
    240 	file_op->delta_us = htobe64(file_op->delta_us);
    241 	file_op->op_union.enum_size = htobe32(file_op->op_union.enum_size);
    242 	file_op->fileno = htobe64(file_op->fileno);
    243 	switch (op) {
    244 	case IOSHARK_LSEEK:
    245 	case IOSHARK_LLSEEK:
    246 		file_op->lseek_offset = htobe64(file_op->lseek_offset);
    247 		file_op->lseek_action = htobe32(file_op->lseek_action);
    248 		break;
    249 	case IOSHARK_PREAD64:
    250 	case IOSHARK_PWRITE64:
    251 		file_op->prw_offset = htobe64(file_op->prw_offset);
    252 		file_op->prw_len = htobe64(file_op->prw_len);
    253 		break;
    254 	case IOSHARK_READ:
    255 	case IOSHARK_WRITE:
    256 		file_op->rw_len = htobe64(file_op->rw_len);
    257 		break;
    258 	case IOSHARK_MMAP:
    259 	case IOSHARK_MMAP2:
    260 		file_op->mmap_offset = htobe64(file_op->mmap_offset);
    261 		file_op->mmap_len = htobe64(file_op->mmap_len);
    262 		file_op->mmap_prot = htobe32(file_op->mmap_prot);
    263 		break;
    264 	case IOSHARK_OPEN:
    265 		file_op->open_flags = htobe32(file_op->open_flags);
    266 		file_op->open_mode = htobe32(file_op->open_mode);
    267 		break;
    268 	case IOSHARK_FSYNC:
    269 	case IOSHARK_FDATASYNC:
    270 		break;
    271 	case IOSHARK_CLOSE:
    272 		break;
    273 	default:
    274 		fprintf(stderr, "%s: unknown FILE_OP %d\n",
    275 			progname, op);
    276 		exit(EXIT_FAILURE);
    277 		break;
    278 	}
    279 	return fwrite(file_op, sizeof(struct ioshark_file_operation), 1, fp);
    280 }
    281