Skip to content

Commit

Permalink
introduce CxxSquidProfiler for CxxSquidSensor
Browse files Browse the repository at this point in the history
* if property set, print duration of each SquidCheck to `sonar.cxx.squidprofiler.out=<abs path>`
* currently only duration is logged
* for parallel execution we can log start/stop time also, in order to check
  the utilization level (see SonarOpenCommunity#1493)

* output: semi-JSON format for later python analysis (e.g. in http://jupyter.org/)
  `{ "visitor": "%s", "source_file": "%s", "duration_ms": "%d" }`
  • Loading branch information
ivangalkin committed Jun 25, 2018
1 parent 72af628 commit a1d6558
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<Grammar> {
protected SquidAstVisitor<Grammar> v;
private long startTimestamp = 0;
private File outFile;

public CxxProfilerDecorator_AstVisitor(SquidAstVisitor<Grammar> visitor, File outF) {
v = visitor;
outFile = outF;
}

@Override
public void setContext(SquidAstVisitorContext<Grammar> context) {
v.setContext(context);
}

@Override
public SquidAstVisitorContext<Grammar> getContext() {
return v.getContext();
}

@Override
public void init() {
v.init();
}

@Override
public void destroy() {
v.destroy();
}

@Override
public List<AstNodeType> 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<Grammar> visitor, File outFile) {
super(visitor, outFile);
}

@Override
public void visitToken(Token token) {
((AstAndTokenVisitor) v).visitToken(token);
}
}

public static SquidAstVisitor<Grammar> decorate(SquidAstVisitor<Grammar> v, File outFile) {
if (v instanceof AstAndTokenVisitor) {
return new CxxProfilerDecorator_AstAndTokenVisitor(v, outFile);
} else {
return new CxxProfilerDecorator_AstVisitor(v, outFile);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -158,6 +159,17 @@ public void execute(SensorContext context) {
}

CxxConfiguration cxxConf = createConfiguration(context.fileSystem(), context);

Optional<String> squidProfilerOutOption = this.language.getStringOption("squidprofiler.out");
if (squidProfilerOutOption.isPresent()) {
File outputPath = new File(squidProfilerOutOption.get());
List<SquidAstVisitor<Grammar>> decoratedVisitors = new ArrayList<>();
for (SquidAstVisitor<Grammar> originalVisitor : visitors) {
decoratedVisitors.add(CxxSquidProfiler.decorate(originalVisitor, outputPath));
}
visitors = decoratedVisitors;
}

AstScanner<Grammar> scanner = CxxAstScanner.create(this.language, cxxConf,
visitors.toArray(new SquidAstVisitor[visitors.size()]));

Expand Down

0 comments on commit a1d6558

Please sign in to comment.