| /************************************************************************** |
| * |
| * Copyright 2015 Alexander Trukhin |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| * THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| #include <iostream> |
| |
| #include "metric_writer.hpp" |
| |
| void ProfilerQuery::writeMetricHeaderCallback(Metric* metric, int event, void* data, int error, |
| void* userData) { |
| std::cout << "\t" << metric->name(); |
| } |
| |
| void ProfilerQuery::writeMetricEntryCallback(Metric* metric, int event, void* data, int error, |
| void* userData) { |
| if (error) { |
| std::cout << "\t" << "#ERR" << error; |
| return; |
| } |
| if (!data) { |
| std::cout << "\t" << "-"; |
| return; |
| } |
| switch(metric->numType()) { |
| case CNT_NUM_UINT: std::cout << "\t" << *(reinterpret_cast<unsigned*>(data)); break; |
| case CNT_NUM_FLOAT: std::cout << "\t" << *(reinterpret_cast<float*>(data)); break; |
| case CNT_NUM_DOUBLE: std::cout << "\t" << *(reinterpret_cast<double*>(data)); break; |
| case CNT_NUM_BOOL: std::cout << "\t" << *(reinterpret_cast<bool*>(data)); break; |
| case CNT_NUM_UINT64: std::cout << "\t" << *(reinterpret_cast<uint64_t*>(data)); break; |
| case CNT_NUM_INT64: std::cout << "\t" << *(reinterpret_cast<int64_t*>(data)); break; |
| } |
| } |
| |
| void ProfilerQuery::writeMetricHeader(QueryBoundary qb) const { |
| for (auto &a : *metricBackends) { |
| a->enumDataQueryId(eventId, &writeMetricHeaderCallback, qb); |
| } |
| std::cout << std::endl; |
| } |
| |
| void ProfilerQuery::writeMetricEntry(QueryBoundary qb) const { |
| for (auto &a : *metricBackends) { |
| a->enumDataQueryId(eventId, &writeMetricEntryCallback, qb); |
| } |
| std::cout << std::endl; |
| } |
| |
| template<typename T> |
| T ProfilerCall::StringTable<T>::getId(const std::string &str) { |
| auto res = stringLookupTable.find(str); |
| T index; |
| if (res == stringLookupTable.end()) { |
| index = static_cast<T>(strings.size()); |
| strings.push_back(str); |
| stringLookupTable[str] = index; |
| } else { |
| index = res->second; |
| } |
| return index; |
| } |
| |
| template<typename T> |
| std::string ProfilerCall::StringTable<T>::getString(T id) { |
| return strings[static_cast<typename decltype(stringLookupTable)::size_type>(id)]; |
| } |
| |
| |
| ProfilerCall::ProfilerCall(unsigned eventId, const data* queryData) |
| : ProfilerQuery(QUERY_BOUNDARY_CALL, eventId) |
| { |
| if (queryData) { |
| isFrameEnd = queryData->isFrameEnd; |
| no = queryData->no; |
| program = queryData->program; |
| nameTableEntry = nameTable.getId(queryData->name); |
| } |
| } |
| |
| |
| void ProfilerCall::writeHeader() const { |
| std::cout << "#\tcall no\tprogram\tname"; |
| ProfilerQuery::writeMetricHeader(QUERY_BOUNDARY_CALL); |
| } |
| |
| void ProfilerCall::writeEntry() const { |
| if (isFrameEnd) { |
| std::cout << "frame_end" << std::endl; |
| } else { |
| std::cout << "call" |
| << "\t" << no |
| << "\t" << program |
| << "\t" << nameTable.getString(nameTableEntry); |
| ProfilerQuery::writeMetricEntry(QUERY_BOUNDARY_CALL); |
| } |
| } |
| |
| |
| void ProfilerDrawcall::writeHeader() const { |
| std::cout << "#\tcall no\tprogram\tname"; |
| ProfilerQuery::writeMetricHeader(QUERY_BOUNDARY_DRAWCALL); |
| } |
| |
| void ProfilerDrawcall::writeEntry() const { |
| if (isFrameEnd) { |
| std::cout << "frame_end" << std::endl; |
| } else { |
| std::cout << "call" |
| << "\t" << no |
| << "\t" << program |
| << "\t" << nameTable.getString(nameTableEntry); |
| ProfilerQuery::writeMetricEntry(QUERY_BOUNDARY_DRAWCALL); |
| } |
| } |
| |
| |
| void ProfilerFrame::writeHeader() const { |
| std::cout << "#"; |
| ProfilerQuery::writeMetricHeader(QUERY_BOUNDARY_FRAME); |
| } |
| |
| void ProfilerFrame::writeEntry() const { |
| std::cout << "frame"; |
| ProfilerQuery::writeMetricEntry(QUERY_BOUNDARY_FRAME); |
| } |
| |
| |
| MetricWriter::MetricWriter(std::vector<MetricBackend*> &metricBackends, |
| const MmapAllocator<char> &alloc) |
| : frameQueue(MmapAllocator<ProfilerCall>(alloc)), |
| callQueue(MmapAllocator<ProfilerCall>(alloc)), |
| drawcallQueue(MmapAllocator<ProfilerCall>(alloc)) |
| { |
| ProfilerQuery::metricBackends = &metricBackends; |
| } |
| |
| void MetricWriter::addQuery(QueryBoundary boundary, unsigned eventId, |
| const void* queryData) |
| { |
| switch (boundary) { |
| case QUERY_BOUNDARY_FRAME: |
| frameQueue.emplace_back(eventId); |
| break; |
| case QUERY_BOUNDARY_CALL: |
| callQueue.emplace_back(eventId, |
| reinterpret_cast<const ProfilerCall::data*>(queryData)); |
| break; |
| case QUERY_BOUNDARY_DRAWCALL: |
| drawcallQueue.emplace_back(eventId, |
| reinterpret_cast<const ProfilerCall::data*>(queryData)); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void MetricWriter::writeQuery(QueryBoundary boundary) { |
| switch (boundary) { |
| case QUERY_BOUNDARY_FRAME: |
| frameQueue.front().writeEntry(); |
| frameQueue.pop_front(); |
| break; |
| case QUERY_BOUNDARY_CALL: |
| callQueue.front().writeEntry(); |
| callQueue.pop_front(); |
| break; |
| case QUERY_BOUNDARY_DRAWCALL: |
| drawcallQueue.front().writeEntry(); |
| drawcallQueue.pop_front(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void MetricWriter::writeAll(QueryBoundary boundary) { |
| switch (boundary) { |
| case QUERY_BOUNDARY_FRAME: |
| frameQueue.front().writeHeader(); |
| while (!frameQueue.empty()) { |
| writeQuery(boundary); |
| } |
| break; |
| case QUERY_BOUNDARY_CALL: |
| callQueue.front().writeHeader(); |
| while (!callQueue.empty()) { |
| writeQuery(boundary); |
| } |
| break; |
| case QUERY_BOUNDARY_DRAWCALL: |
| drawcallQueue.front().writeHeader(); |
| while (!drawcallQueue.empty()) { |
| writeQuery(boundary); |
| } |
| break; |
| default: |
| break; |
| } |
| std::cout << std::endl; |
| } |
| |
| std::vector<MetricBackend*>* ProfilerQuery::metricBackends = nullptr; |
| |
| ProfilerCall::StringTable<int16_t> ProfilerCall::nameTable; |