1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package ohos.devtools.services.hiperf; 17 18 import ohos.devtools.datasources.transport.grpc.service.HiperfReport; 19 import ohos.devtools.datasources.utils.profilerlog.ProfilerLogManager; 20 import org.apache.logging.log4j.LogManager; 21 import org.apache.logging.log4j.Logger; 22 23 import java.io.File; 24 import java.io.IOException; 25 import java.nio.ByteBuffer; 26 import java.sql.Connection; 27 import java.sql.PreparedStatement; 28 import java.sql.SQLException; 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.Map; 32 import java.util.List; 33 34 /** 35 * Trace File Parse 36 * 37 * @since 2021/8/20 18:00 38 */ 39 public class HiperfParse extends ParsePerf { 40 /** 41 * Log 42 */ 43 private static final Logger LOGGER = LogManager.getLogger(HiperfParse.class); 44 45 /** 46 * File Head Sign 47 */ 48 private static final String HEAD = "HIPERF_PB_"; 49 50 /** 51 * File Struct List 52 */ 53 private final Map<Integer, HiperfReport.SymbolTableFile> mFiles = new HashMap<>(); 54 55 /** 56 * Thread Struct List 57 */ 58 private final Map<Integer, HiperfReport.VirtualThreadInfo> mThreads = new HashMap<>(); 59 60 /** 61 * Sample Struct List 62 */ 63 private final List<HiperfReport.CallStackSample> mSamples = new ArrayList<>(); 64 65 /** 66 * Parse trace File 67 * 68 * @param trace trace file 69 * @throws IOException io 70 */ parseFile(File trace)71 public void parseFile(File trace) throws IOException { 72 if (ProfilerLogManager.isInfoEnabled()) { 73 LOGGER.info("parseFile"); 74 } 75 if (trace == null || !trace.isFile()) { 76 return; 77 } 78 ByteBuffer buffer = byteBufferFromFile(trace); 79 verifyHead(buffer, HEAD); 80 // myTraceVersion 81 buffer.getShort(); 82 int recordSize = buffer.getInt(); 83 long sampleCount = 0L; 84 while (recordSize != 0) { 85 byte[] recordBytes = new byte[recordSize]; 86 buffer.get(recordBytes); 87 HiperfReport.HiperfRecord record = HiperfReport.HiperfRecord.parseFrom(recordBytes); 88 89 switch (record.getRecordTypeCase()) { 90 case FILE: 91 HiperfReport.SymbolTableFile file = record.getFile(); 92 mFiles.put(file.getId(), file); 93 break; 94 case STATISTIC: 95 HiperfReport.SampleStatistic situation = record.getStatistic(); 96 sampleCount = situation.getCount(); 97 break; 98 case SAMPLE: 99 HiperfReport.CallStackSample sample = record.getSample(); 100 mSamples.add(sample); 101 break; 102 case THREAD: 103 HiperfReport.VirtualThreadInfo thread = record.getThread(); 104 mThreads.put(thread.getTid(), thread); 105 break; 106 default: 107 LOGGER.info("Lost Case"); 108 } 109 recordSize = buffer.getInt(); 110 } 111 112 if (mSamples.size() != sampleCount) { 113 throw new IllegalStateException("Samples count doesn't match the number of samples read."); 114 } 115 } 116 117 /** 118 * insertPerfSample 119 */ insertSample()120 public void insertSample() { 121 Connection conn = PerfDAO.getInstance().getConn(); 122 try { 123 PreparedStatement callChainPst = conn.prepareStatement( 124 "insert into " 125 + "perf_callchain(" 126 + "sample_id, " 127 + "callchain_id, " 128 + "vaddr_in_file, " 129 + "file_id, " 130 + "symbol_id) " 131 + "values(?,?,?,?,?)"); 132 conn.setAutoCommit(false); 133 134 PreparedStatement samplePst = conn.prepareStatement( 135 "insert into " 136 + "perf_sample(" 137 + "sample_id, " 138 + "timestamp, " 139 + "thread_id, " 140 + "event_count, " 141 + "event_type_id) " 142 + "values(?,?,?,?,?)"); 143 conn.setAutoCommit(false); 144 145 // sample 146 getSamplePst(samplePst, callChainPst); 147 148 // files 149 PreparedStatement filePst = getFilePst(conn); 150 // thread 151 PreparedStatement threadPst = getThreadPst(conn); 152 try { 153 samplePst.executeBatch(); 154 callChainPst.executeBatch(); 155 filePst.executeBatch(); 156 threadPst.executeBatch(); 157 conn.commit(); 158 } catch (SQLException exception) { 159 if (ProfilerLogManager.isErrorEnabled()) { 160 LOGGER.error(exception.getMessage()); 161 } 162 } finally { 163 if (samplePst != null) { 164 samplePst.close(); 165 } 166 conn.close(); 167 } 168 } catch (SQLException exception) { 169 if (ProfilerLogManager.isErrorEnabled()) { 170 LOGGER.error(exception.getMessage()); 171 } 172 } 173 } 174 175 getThreadPst(Connection conn)176 private PreparedStatement getThreadPst(Connection conn) throws SQLException { 177 PreparedStatement threadPst = conn.prepareStatement( 178 "insert into " 179 + "perf_thread(" 180 + "thread_id, " 181 + "process_id, " 182 + "thread_name) " 183 + "values(?,?,?)"); 184 conn.setAutoCommit(false); 185 mThreads.values().forEach(thread -> { 186 try { 187 threadPst.setInt(1, thread.getTid()); 188 threadPst.setInt(2, thread.getPid()); 189 threadPst.setString(3, thread.getName()); 190 threadPst.addBatch(); 191 } catch (SQLException exception) { 192 if (ProfilerLogManager.isErrorEnabled()) { 193 LOGGER.error(exception.getMessage()); 194 } 195 } 196 }); 197 return threadPst; 198 } 199 getFilePst(Connection conn)200 private PreparedStatement getFilePst(Connection conn) throws SQLException { 201 PreparedStatement filePst = conn.prepareStatement( 202 "insert into " 203 + "perf_files(" 204 + "file_id, " 205 + "symbol, " 206 + "path) " 207 + "values(?,?,?)"); 208 conn.setAutoCommit(false); 209 mFiles.values().forEach(perffile -> { 210 perffile.getFunctionNameList().forEach(function -> { 211 try { 212 filePst.setInt(1, perffile.getId()); 213 filePst.setString(2, function); 214 filePst.setString(3, perffile.getPath()); 215 filePst.addBatch(); 216 } catch (SQLException exception) { 217 if (ProfilerLogManager.isErrorEnabled()) { 218 LOGGER.error(exception.getMessage()); 219 } 220 } 221 }); 222 }); 223 return filePst; 224 } 225 getSamplePst(PreparedStatement samplePst, PreparedStatement callChainPst)226 private void getSamplePst(PreparedStatement samplePst, PreparedStatement callChainPst) { 227 for (int sampleId = 0; sampleId < mSamples.size(); sampleId++) { 228 HiperfReport.CallStackSample sample = mSamples.get(sampleId); 229 try { 230 samplePst.setLong(1, sampleId); 231 samplePst.setLong(2, sample.getTime()); 232 samplePst.setInt(3, sample.getTid()); 233 samplePst.setLong(4, sample.getEventCount()); 234 samplePst.setInt(5, sample.getConfigNameId()); 235 samplePst.addBatch(); 236 for (int callChainId = 0; callChainId < sample.getCallStackFrameList().size(); callChainId++) { 237 HiperfReport.CallStackSample.CallStackFrame callChain = 238 sample.getCallStackFrameList().get(callChainId); 239 callChainPst.setLong(1, sampleId); 240 callChainPst.setLong(2, callChainId); 241 callChainPst.setLong(3, callChain.getSymbolsVaddr()); 242 callChainPst.setLong(4, callChain.getSymbolsFileId()); 243 callChainPst.setInt(5, callChain.getFunctionNameId()); 244 callChainPst.addBatch(); 245 } 246 } catch (SQLException exception) { 247 if (ProfilerLogManager.isErrorEnabled()) { 248 LOGGER.error(exception.getMessage()); 249 } 250 } 251 } 252 } 253 } 254