Beispiel #1
0
/* \param xdf	pointer of a valid xdf file
 *
 * Allocate all the buffers and temporary objects needed for the transfer
 */
static int alloc_transfer_objects(struct xdf* xdf)
{
	unsigned int samsize;
	xdf->sample_size = samsize = compute_sample_size(xdf, 1);
	xdf->filerec_size = compute_sample_size(xdf, 0) * xdf->ns_per_rec;

	if ( !(xdf->convdata = malloc(xdf->numch*sizeof(*(xdf->convdata))))
	    || !(xdf->batch = malloc(xdf->nbatch*sizeof(*(xdf->batch))))  
	    || !(xdf->buff = malloc(xdf->ns_per_rec * samsize)) 
	    || !(xdf->backbuff = malloc(xdf->ns_per_rec * samsize)) 
	    || !(xdf->tmpbuff[0] = malloc(xdf->ns_per_rec * 8)) 
	    || !(xdf->tmpbuff[1] = malloc(xdf->ns_per_rec * 8)) ) {
		return -1;
	}
	return 0;
}
Beispiel #2
0
/*
 * Arguments:
 * -i  input file. Default: perf.data.
 */
int
main(int argc, char **argv)
{
    int ret, c;
    char *input_fname = "perf.data";
    char *output_fname = "perf.data.manicured";
    char *optval = NULL;

    perf_file_header f_header, f_header_manicured;


    while ((c = getopt (argc, argv, "b:e:i:o:s:")) != -1)
    {
	switch(c)
	{
	case 'b':
	    begin_time = parse_timestamp_and_exit_on_error(optarg, "begin");
	    break;
	case 'e':
	    end_time = parse_timestamp_and_exit_on_error(optarg, "end");
	    break;
	case 'i':
	    input_fname = optarg;
	    break;
	case 'o':
	    output_fname = optarg;
	    break;
	case 's':
	    user_base_time = parse_timestamp_and_exit_on_error(optarg, "start");
	    break;
	case '?':
	default:
	    usage(argv[0]);
	    exit(-1);
	}
    }

    printf("Begin timestamp: %" PRIu64 " \n" 
	   "End timestamp: %" PRIu64 " \n" 
	   "Start (of program) timestamp: %" PRIu64 " \n", 
	   begin_time, end_time, user_base_time);

    if(user_base_time == 0 && (begin_time != 0))
	printf("Warning: zero starting timestamp provided. Your begin and end timestamps will not be correctly "
	       "calibrated to perf timestamps.\n");

    if(begin_time < user_base_time || end_time < user_base_time)
    {
	printf("Your begin or end timestamps are smaller than the starting timestamp. Cannot proceed.\n");
	usage(argv[0]);
	exit(-1);
    }

    /* Let's reset begin and end timestamps to be relative to the start-of-program timestamp,
     * so we don't have to perform this computation on every event.
     */
    begin_time -= user_base_time;
    end_time -= user_base_time;
    
    int ifd = open(input_fname, O_RDONLY);
    if(ifd == -1)
    {	
	fprintf(stderr, "Could not open %s: %s\n", input_fname, strerror(errno));
	usage(argv[0]);
	exit(-1);		
    }

    int ofd = open(output_fname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    if(ofd == -1)
    {
	fprintf(stderr, "Could not open %s: %s\n", output_fname, strerror(errno));
	usage(argv[0]);
	exit(-1);		
    }


    ret = check_and_copy_header(ifd, ofd, &f_header);
    if(ret)
	exit(-1);		
    printf("Successful header check...\n");

    
    /*
     * Sanity check that perf.data was written cleanly; data size is
     * initialized to 0 and updated only if the on_exit function is run.
     * If data size is still 0 then the file contains only partial
     * information.  Just warn user and process it as much as it can.
     */
    if (f_header.data.size == 0) {
	fprintf(stderr, "WARNING: The %s file's data size field is 0 which is unexpected.\n"
		"Was the 'perf record' command properly terminated?\n",
		input_fname);
    }

    /* Copy the event attribute section */
    {
	
	/* SANITY CHECK.
	 * If these two quantities are not equal, we must
	 * be processing the perf file format that this tool
	 * does not support. 
	 */

	if(f_header.attr_size != sizeof(struct perf_file_attr))
	{
	    fprintf(stderr, "header attr_size (%" PRIu64 ") not equal to "
		    "the size of struct perf_file_attr (%" PRIu64 "). "
		    "Your perf.data file  is the format that this tool "
		    "does not understand. Sorry!\n", 
		    f_header.attr_size, sizeof(struct perf_file_attr));
	    exit(-1);
	}

	/* Now read and copy file sections corresponding to individual attributes. 
	 * We read and copy attributes one by one, because each attribute contains
	 * a pointer to another file location containing more data. And we need to
	 * copy that data as well. 
	 */
	int i, nr_attrs = f_header.attrs.size / f_header.attr_size;
	for(i = 0; i < nr_attrs; i++)
	{
	    perf_file_attr f_attr;
	    struct perf_event_attr *attr = &(f_attr.attr);

	    lseek(ifd, f_header.attrs.offset + i*f_header.attr_size, SEEK_SET);
	    lseek(ofd, f_header.attrs.offset + i*f_header.attr_size, SEEK_SET);

	    read_and_exit_on_error(ifd,  &f_attr, f_header.attr_size, __FILE__, __LINE__); 
	    write_and_exit_on_error(ofd, &f_attr, f_header.attr_size, __FILE__, __LINE__);

	    printf("Set to offset %ld and read %ld bytes of perf_file_attr (%ld size)\n", 
		   f_header.attrs.offset + i*f_header.attr_size, f_header.attr_size, 
		   sizeof(f_attr));
	 	    
	    if(f_attr.ids.size > 0)
	    {
		printf("There's %" PRId64 " bytes of data at offset %" PRId64 "\n", 
		       f_attr.ids.size, 		   
		       f_attr.ids.offset);

		void *buffer = malloc_and_exit_on_error(f_attr.ids.size, __FILE__, __LINE__);
		
		lseek(ifd, f_attr.ids.offset, SEEK_SET);
		lseek(ofd, f_attr.ids.offset, SEEK_SET);

		read_and_exit_on_error(ifd,  buffer, f_attr.ids.size, __FILE__, __LINE__); 
		write_and_exit_on_error(ofd, buffer, f_attr.ids.size, __FILE__, __LINE__); 
	    
		free(buffer);
	    }

	    if(!(attr->sample_type & PERF_SAMPLE_TIME) && !attr->sample_id_all)
	    {
		fprintf(stderr, "Event %s does not sample time. "
			"We do not know how to process such events.\n", 
			attr->type < PERF_TYPE_MAX ? event_attr_names[attr->type]: "UNKNOWN");
		exit(-1);
	    }

	    /* Keep this event attribute in the list. We will later use them to parse samples.
	     * Technically, we need only the first one (see comment in event_do_we_care()), but
	     * let's keep them all just in case. 
	     */
	    event_descr *attr_to_keep = 
		malloc_and_exit_on_error(sizeof(event_descr), __FILE__, __LINE__);

	    attr_to_keep->attr = *attr;	    
	    attr_to_keep->sample_size = compute_sample_size(attr->sample_type);
	    list_insert_and_exit_on_error(&event_attr_list, (void*)attr_to_keep, __FILE__, __LINE__);

	    printf("Found event %s, sample type is %" PRIu64 ", sample size is %" PRIu64 "\n",
		   attr->type < PERF_TYPE_MAX ? event_attr_names[attr->type]: "UNKNOWN",
		   attr->sample_type, attr_to_keep->sample_size);
	    char *what_we_are_sampling = what_are_we_sampling(attr->sample_type);
	    printf("%s\n", what_we_are_sampling);
	    free(what_we_are_sampling);

	    if(!attr->sample_id_all)
	    {
		fprintf(stderr, "This perf file does not have sample IDs for all data "
			"(sample_id_all not set on an event attribute)."
			"We rely on sample id timestamp in the COMM event to calibrate "
			"timestamps, so this program won't work without sample id data. "
			"Try using a more recent version of perf. Sorry!\n");
		exit(-1);
	    }
	}
    }
	
    /* Copy the event section */
    {
	void *buffer = malloc_and_exit_on_error(f_header.event_types.size, __FILE__, __LINE__);
	    
	lseek(ifd, f_header.event_types.offset, SEEK_SET);
	lseek(ofd, f_header.event_types.offset, SEEK_SET);
	
	read_and_exit_on_error(ifd,  buffer, f_header.event_types.size, __FILE__, __LINE__);
	write_and_exit_on_error(ofd, buffer, f_header.event_types.size, __FILE__, __LINE__);

	printf("read event_types: %ld bytes at offset %ld\n", f_header.event_types.size, 
	       f_header.event_types.offset);
	
	free(buffer);
    }
    
    /* Cull the data section. 
     * This section is structured as a collection of perf_event records. Each
     * record begins with a header, which has a size field. We don't know in advance how large a 
     * record is or how it is structured.
     * So we are going to read the header first to find out the size and type, and then we read
     * the rest. 
     */
    {
	size_t bytes_processed = 0, bytes_written_to_manicured_file = 0;

	/* We position the input and output file at the start of the data section, 
	 * but from now on, the files may not be moving synchronously if we are
	 * copying only selected records to the output file.
	 */
	lseek(ifd, f_header.data.offset, SEEK_SET);
	lseek(ofd, f_header.data.offset, SEEK_SET);

	/* We now copy records one by one and decide if we care about them. */
	while(bytes_processed < f_header.data.size)
	{
	    union perf_event *event;
	    perf_event_header *event_header = (perf_event_header*) &event; 
	    size_t this_event_size;

	    read_and_exit_on_error(ifd, &event, sizeof(perf_event_header), __FILE__, __LINE__);

	    /* Ok, now we know the size of this event record */
	    this_event_size = event_header->size;

	    event = malloc(this_event_size);

	    /* Read the entire event from the file. 
	     * We don't have to re-read the header, because we already have it, 
	     * but let's do it anyway, this makes the code simpler.
	     */
	    lseek(ifd, -sizeof(perf_event_header), SEEK_CUR);
	    read_and_exit_on_error(ifd, event, this_event_size, __FILE__, __LINE__);

	    /* Ok, now determine if we care about this event. 
	     * Its timestamp must fall between the begin and end timestamps
	     * supplied as arguments. 
	     */
	    if(event_do_we_care(event, begin_time, end_time))
	    {
		write_and_exit_on_error(ofd, event, this_event_size, __FILE__, __LINE__);
		bytes_written_to_manicured_file += this_event_size;
	    }	    
	    
	    bytes_processed += this_event_size;
	    printf("IF offset: %ld, OF offset: %ld\n,", lseek(ifd, 0, SEEK_CUR), 
		   lseek(ofd, 0, SEEK_CUR));

	    free(event);

	}


	printf("data section: %ld bytes at offset %ld. Processed %ld bytes \n", 
	       f_header.data.size, f_header.data.offset, bytes_processed);

	/* Now let's re-write the file header section of the output file
	 * to update the data section size.
	 */
	f_header_manicured = f_header;
	f_header_manicured.data.size = bytes_written_to_manicured_file;

	lseek(ofd, 0, SEEK_SET);
	write_and_exit_on_error(ofd, &f_header_manicured, sizeof(perf_file_header), __FILE__, __LINE__);

    }

    /* Copy the additional features section.
     * This section begins at the end of the data section and has a number of 
     * records of type perf_file_section. How many records there are is determined
     * by the number of set bits in the adds_features bitmap in the file header. 
     * 
     * If we have not copied the entire data section from the input file to the
     * output file, the output file will have a hole in it. That's ok. 
     * 
     * These additional features (defined in tools/perf/util/header.h) include
     * things like hostname, OS release, NUMA topology, etc. So we copy them
     * unchanged into the manicured file. 
     */
    {
	size_t feat_offset = f_header.data.offset + f_header.data.size;
	int i, nr_records; 

	nr_records = bitmap_weight(f_header.adds_features, HEADER_FEAT_BITS);
	
	/* Each record in this section is a perf_file_section, so it
	 * has a pointer to another file location with data. So we
	 * process these records one by one and copy the record itself and 
	 * the data to which it points. 
	 */
	for(i = 0; i < nr_records; i++)
	{
	    perf_file_section rec;

	    /* For the output file we use the same offset as the
	     * one in the original input file, even though the 
	     * manicured output file is most likely shorter than
	     * the original (because we skipped data records). 
	     * That is probably okay. Only means that our output file
	     * will have a "hole" in it. 
	     */

	    lseek(ifd, feat_offset + i * sizeof(rec), SEEK_SET);
	    lseek(ofd, feat_offset + i * sizeof(rec), SEEK_SET);

	    read_and_exit_on_error(ifd,  &rec, sizeof(rec), __FILE__, __LINE__);
	    write_and_exit_on_error(ofd, &rec, sizeof(rec), __FILE__, __LINE__);

	    printf("Adds feats: read %ld bytes at offset %ld\n", sizeof(rec), 
		   feat_offset + i * sizeof(rec));

	    printf("There's %ld more bytes at offset %ld\n", rec.size, rec.offset);

	    lseek(ifd, rec.offset, SEEK_SET);
	    lseek(ofd, rec.offset, SEEK_SET);

	    void *buffer = malloc_and_exit_on_error(rec.size, __FILE__, __LINE__);

	    read_and_exit_on_error(ifd,  buffer, rec.size, __FILE__, __LINE__);
	    write_and_exit_on_error(ofd, buffer, rec.size, __FILE__, __LINE__);
	    
	    free(buffer);
	}
	
    }

}