From a1d655835949fa7ed7b68a9a822a63fb0268d8d2 Mon Sep 17 00:00:00 2001 From: Ivan Galkin Date: Mon, 25 Jun 2018 23:10:59 +0200 Subject: [PATCH] introduce CxxSquidProfiler for CxxSquidSensor * if property set, print duration of each SquidCheck to `sonar.cxx.squidprofiler.out=` * currently only duration is logged * for parallel execution we can log start/stop time also, in order to check the utilization level (see #1493) * output: semi-JSON format for later python analysis (e.g. in http://jupyter.org/) `{ "visitor": "%s", "source_file": "%s", "duration_ms": "%d" }` --- .../cxx/sensors/squid/CxxSquidProfiler.java | 142 ++++++++++++++++++ .../cxx/sensors/squid/CxxSquidSensor.java | 12 ++ 2 files changed, 154 insertions(+) create mode 100644 cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidProfiler.java diff --git a/cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidProfiler.java b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidProfiler.java new file mode 100644 index 0000000000..b80e62e94a --- /dev/null +++ b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidProfiler.java @@ -0,0 +1,142 @@ +/* + * Sonar C++ Plugin (Community) + * Copyright (C) 2010-2018 SonarOpenCommunity + * http://github.com/SonarOpenCommunity/sonar-cxx + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.cxx.sensors.squid; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + +import org.apache.commons.io.FileUtils; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.squidbridge.SquidAstVisitor; +import org.sonar.squidbridge.SquidAstVisitorContext; + +import com.sonar.sslr.api.AstAndTokenVisitor; +import com.sonar.sslr.api.AstNode; +import com.sonar.sslr.api.AstNodeType; +import com.sonar.sslr.api.Grammar; +import com.sonar.sslr.api.Token; + +public class CxxSquidProfiler { + private static final Logger LOG = Loggers.get(CxxSquidProfiler.class); + + public static class CxxProfilerDecorator_AstVisitor extends SquidAstVisitor { + protected SquidAstVisitor v; + private long startTimestamp = 0; + private File outFile; + + public CxxProfilerDecorator_AstVisitor(SquidAstVisitor visitor, File outF) { + v = visitor; + outFile = outF; + } + + @Override + public void setContext(SquidAstVisitorContext context) { + v.setContext(context); + } + + @Override + public SquidAstVisitorContext getContext() { + return v.getContext(); + } + + @Override + public void init() { + v.init(); + } + + @Override + public void destroy() { + v.destroy(); + } + + @Override + public List getAstNodeTypesToVisit() { + return v.getAstNodeTypesToVisit(); + } + + protected void writeEvent(long nanoDuration) { + String path = "null"; + if (getContext() != null && getContext().getFile() != null) { + path = getContext().getFile().getAbsolutePath(); + } + String classname = v.getClass().getName(); + String entry = String.format("{ \"visitor\": \"%s\", \"source_file\": \"%s\", \"duration_ms\": \"%d\" }\n", + classname, path, + TimeUnit.NANOSECONDS.toMillis(nanoDuration)); + + try { + FileUtils.writeStringToFile(outFile, entry, Charset.defaultCharset(), true); + } catch (IOException e) { + LOG.debug("Cannot write bench information: {}", e); + } + } + + @Override + public void visitFile(@Nullable AstNode ast) { + startTimestamp = System.nanoTime(); + v.visitFile(ast); + } + + @Override + public void leaveFile(@Nullable AstNode ast) { + v.leaveFile(ast); + long nanoDuration = System.nanoTime() - startTimestamp; + writeEvent(nanoDuration); + } + + @Override + public void visitNode(AstNode ast) { + v.visitNode(ast); + } + + @Override + public void leaveNode(AstNode ast) { + v.leaveNode(ast); + } + } + + public static class CxxProfilerDecorator_AstAndTokenVisitor extends CxxProfilerDecorator_AstVisitor + implements AstAndTokenVisitor { + + public CxxProfilerDecorator_AstAndTokenVisitor(SquidAstVisitor visitor, File outFile) { + super(visitor, outFile); + } + + @Override + public void visitToken(Token token) { + ((AstAndTokenVisitor) v).visitToken(token); + } + } + + public static SquidAstVisitor decorate(SquidAstVisitor v, File outFile) { + if (v instanceof AstAndTokenVisitor) { + return new CxxProfilerDecorator_AstAndTokenVisitor(v, outFile); + } else { + return new CxxProfilerDecorator_AstVisitor(v, outFile); + } + } + +} diff --git a/cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidSensor.java b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidSensor.java index fa1f33e51a..f7a2d1f8b7 100644 --- a/cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidSensor.java +++ b/cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidSensor.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.Optional; import javax.annotation.Nullable; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; @@ -158,6 +159,17 @@ public void execute(SensorContext context) { } CxxConfiguration cxxConf = createConfiguration(context.fileSystem(), context); + + Optional squidProfilerOutOption = this.language.getStringOption("squidprofiler.out"); + if (squidProfilerOutOption.isPresent()) { + File outputPath = new File(squidProfilerOutOption.get()); + List> decoratedVisitors = new ArrayList<>(); + for (SquidAstVisitor originalVisitor : visitors) { + decoratedVisitors.add(CxxSquidProfiler.decorate(originalVisitor, outputPath)); + } + visitors = decoratedVisitors; + } + AstScanner scanner = CxxAstScanner.create(this.language, cxxConf, visitors.toArray(new SquidAstVisitor[visitors.size()]));