예제 #1
0
void TraceData::parseReport(const std::string& filename)
{
	release();

	std::ifstream file;
	std::istream& in = filename.empty() ? std::cin : file;
	if (!filename.empty()) {
		file.open(filename.c_str(), std::ios_base::in);
		if (file.fail()) {
			throw std::ios_base::failure(Formatter() << "Failed to open file: " << filename);
		}
	}
	char buffer[4096];

	in.getline(buffer, sizeof(buffer));
	if (in.eof()) throw std::runtime_error(Formatter() << "Empty input file: " << filename);

	if (buffer[0] == (char)SP_RTRACE_PROTO_HS_ID) {
		throw std::runtime_error("Can't process sp-rtrace binary files. "
				                 "Convert to text format with sp-rtrace-postproc and try again.");
	}

	sp_rtrace_parser_parse_header(buffer, &header);

	while (true && (filename_maps.empty() || filename_pageflags.empty()) ) {
		in.getline(buffer, sizeof(buffer));
		if (in.eof()) break;

		sp_rtrace_record_t rec;
		int rec_type = sp_rtrace_parser_parse_record(buffer, &rec);
		switch (rec_type) {
			case SP_RTRACE_RECORD_ATTACHMENT:
				if (!strcmp(rec.attachment.name, ATTACHMENT_MAPS)) filename_maps = rec.attachment.path;
				else if (!strcmp(rec.attachment.name, ATTACHMENT_PAGEFLAGS)) filename_pageflags = rec.attachment.path;
				break;
		}
		sp_rtrace_parser_free_record(rec_type, &rec);
	}

	if (access(filename_maps.c_str(), F_OK) == -1) throw std::runtime_error(Formatter() << "Failed to access maps file '" << filename_maps << "': " << strerror(errno));
	if (access(filename_pageflags.c_str(), F_OK) == -1) throw std::runtime_error(Formatter() << "Failed to access pageflags file '" << filename_pageflags << "': " << strerror(errno));

	// map the pageflags file to memory
	pageflags_fd = open(filename_pageflags.c_str(), O_RDONLY);
	if (pageflags_fd == -1) throw std::runtime_error(Formatter() << "Failed to open pageflags file '" << filename_pageflags << "': " << strerror(errno));

	struct stat ps;
	if (fstat(pageflags_fd, &ps) ==  -1) throw std::runtime_error(Formatter() << "Failed to stat pageflags file '" << filename_pageflags << "': " << strerror(errno));
	pageflags_size = ps.st_size;

	pageflags_addr = mmap(NULL, pageflags_size, PROT_READ, MAP_SHARED, pageflags_fd, 0);
	if (pageflags_addr == MAP_FAILED) throw std::runtime_error(Formatter() << "Failed to mmap pageflags file '" << filename_pageflags << "': " << strerror(errno));

	// scan the mapped areas from maps/pageflags files
	scanMemoryAreas();

	// scan the allocation events
	in.seekg(0);
	std::list<CallEvent*> last_events;

	sp_rtrace_btframe_t frames[512];
	sp_rtrace_btframe_t* pframe = frames;

	while (true) {
		in.getline(buffer, sizeof(buffer));
		if (in.eof()) break;

		sp_rtrace_record_t rec;
		int rec_type = sp_rtrace_parser_parse_record(buffer, &rec);
		if (rec_type == SP_RTRACE_RECORD_TRACE) {
			/* don't collect backtrace records if there is no preceeding allocation
			 * function event */
			if (last_events.empty()) {
				sp_rtrace_parser_free_record(rec_type, &rec);
			}
			else {
				*pframe++ = rec.frame;
			}
			continue;
		}
		// Store backtrace record for last cached events
		if ((pframe > frames || !*buffer) && !last_events.empty()) {
			storeTrace(last_events, frames, pframe - frames);
			last_events.clear();
		}

		if (rec_type == SP_RTRACE_RECORD_CALL) {
			if (rec.call.type == SP_RTRACE_FTYPE_ALLOC) {
				MemoryArea* area = findMemoryArea(rec.call.res_id);
				if (area) {
					last_events.push_back(area->addEvent(rec.call));
					continue;
				}
			}
		}
		pframe = frames;
		sp_rtrace_parser_free_record(rec_type, &rec);
	}
	if ((pframe > frames || !*buffer) && !last_events.empty()) {
		fprintf(stderr, "last parse\n");
		storeTrace(last_events, frames, pframe - frames);
		last_events.clear();
	}

	// sort the allocation events inside areas
	for (MemoryArea::vector_t::iterator iter = memory_areas.begin(); iter != memory_areas.end(); iter++) {
		iter->get()->sortEvents();
	}
}