Skip to content

Commit

Permalink
Outline of using tracers for profiling
Browse files Browse the repository at this point in the history
  • Loading branch information
thobe authored and Mats-SX committed May 3, 2015
1 parent 5ec6817 commit a24e5f2
Show file tree
Hide file tree
Showing 15 changed files with 560 additions and 25 deletions.
Expand Up @@ -40,13 +40,12 @@
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;


import org.neo4j.cypher.internal.compiler.v2_3.ExecutionMode;
import org.neo4j.cypher.internal.compiler.v2_3.TaskCloser;
import org.neo4j.cypher.internal.compiler.v2_3.executionplan.InternalExecutionResult;
import org.neo4j.cypher.internal.compiler.v2_3.planDescription.InternalPlanDescription;
import org.neo4j.cypher.internal.compiler.v2_3.planner.CantCompileQueryException;
import org.neo4j.function.Supplier;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.kernel.api.Statement;

Expand Down Expand Up @@ -99,12 +98,12 @@ public static Class<InternalExecutionResult> compile( String className, String c
}

public static InternalExecutionResult newInstance( Class<InternalExecutionResult> clazz, TaskCloser closer, Statement statement,
GraphDatabaseService db, ExecutionMode executionMode, InternalPlanDescription description, Map<String, Object> params)
GraphDatabaseService db, ExecutionMode executionMode, Supplier<InternalPlanDescription> description, QueryExecutionTracer tracer, Map<String, Object> params)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException
{
Constructor<InternalExecutionResult> constructor =
clazz.getDeclaredConstructor( TaskCloser.class, Statement.class, GraphDatabaseService.class, ExecutionMode.class, InternalPlanDescription.class , Map.class);
return constructor.newInstance( closer, statement, db, executionMode, description, params );
clazz.getDeclaredConstructor( TaskCloser.class, Statement.class, GraphDatabaseService.class, ExecutionMode.class, Supplier.class, QueryExecutionTracer.class, Map.class);
return constructor.newInstance( closer, statement, db, executionMode, description, tracer, params );
}

private static class InMemSource extends SimpleJavaFileObject
Expand Down
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2002-2015 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.cypher.internal.compiler.v2_3.birk;

import org.neo4j.cypher.internal.compiler.v2_3.planDescription.Id;

public interface QueryExecutionTracer
{
QueryExecutionEvent executeQuery( Id queryId );

QueryExecutionTracer NONE = new QueryExecutionTracer()
{
@Override
public QueryExecutionEvent executeQuery( Id queryId )
{
return QueryExecutionEvent.NONE;
}
};
}
@@ -0,0 +1,167 @@
/*
* Copyright (c) 2002-2015 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.neo4j.cypher.internal.compiler.v2_3.birk.profiling;

import java.util.HashMap;
import java.util.Map;

import org.neo4j.cypher.internal.compiler.v2_3.birk.QueryExecutionEvent;
import org.neo4j.cypher.internal.compiler.v2_3.birk.QueryExecutionTracer;
import org.neo4j.cypher.internal.compiler.v2_3.planDescription.Id;

public class ProfilingTracer implements QueryExecutionTracer
{
public interface ProfilingInformation
{
long time();
long dbHits();
long rows();
}

public interface Clock
{
long nanoTime();

Clock SYSTEM_TIMER = new Clock()
{
@Override
public long nanoTime()
{
return System.nanoTime();
}
};
}

private static final Data ZERO = new Data();

private final Clock clock;
private final Map<Id, Data> data = new HashMap<>();

public ProfilingTracer()
{
this( Clock.SYSTEM_TIMER );
}

ProfilingTracer( Clock clock )
{
this.clock = clock;
}

public ProfilingInformation get( Id query )
{
Data value = data.get( query );
return value == null ? ZERO : value;
}

public long timeOf( Id query )
{
return get( query ).time();
}

public long dbHitsOf( Id query )
{
return get( query ).dbHits();
}

public long rowsOf( Id query )
{
return get( query ).rows();
}

@Override
public QueryExecutionEvent executeQuery( Id queryId )
{
Data data = this.data.get( queryId );
if ( data == null && queryId != null )
{
this.data.put( queryId, data = new Data() );
}
return new ExecutionEvent( clock, data );
}

private static class ExecutionEvent implements QueryExecutionEvent
{
private final long start;
private final Clock clock;
private final Data data;
private long hitCount;
private long rowCount;

public ExecutionEvent( Clock clock, Data data )
{
this.clock = clock;
this.data = data;
this.start = clock.nanoTime();
}

@Override
public void close()
{
long executionTime = clock.nanoTime() - start;
if ( data != null )
{
data.update( executionTime, hitCount, rowCount );
}
}

@Override
public void dbHit()
{
hitCount++;
}

@Override
public void row()
{
rowCount++;
}
}

private static class Data implements ProfilingInformation
{
private long time, hits, rows;

public void update( long time, long hits, long rows )
{
this.time += time;
this.hits += hits;
this.rows += rows;
}

@Override
public long time()
{
return time;
}

@Override
public long dbHits()
{
return hits;
}

@Override
public long rows()
{
return rows;
}
}
}
Expand Up @@ -35,6 +35,7 @@ import org.neo4j.cypher.internal.compiler.v2_3.planner.logical.{LogicalPlan2Plan
import org.neo4j.cypher.internal.compiler.v2_3.planner.{CantCompileQueryException, SemanticTable}
import org.neo4j.cypher.internal.compiler.v2_3.spi.{InstrumentedGraphStatistics, PlanContext}
import org.neo4j.cypher.internal.compiler.v2_3.{ExecutionMode, GreedyPlannerName}
import org.neo4j.function.Supplier
import org.neo4j.graphdb.GraphDatabaseService
import org.neo4j.helpers.Clock
import org.neo4j.kernel.api.Statement
Expand Down Expand Up @@ -114,6 +115,7 @@ object CodeGenerator {
s"""package $packageName;
|
|import org.neo4j.helpers.collection.Visitor;
|import org.neo4j.function.Supplier;
|import org.neo4j.graphdb.GraphDatabaseService;
|import org.neo4j.kernel.api.Statement;
|import org.neo4j.kernel.api.exceptions.KernelException;
Expand All @@ -128,6 +130,8 @@ object CodeGenerator {
|import org.neo4j.cypher.internal.compiler.v2_3.planDescription.InternalPlanDescription;
|import org.neo4j.cypher.internal.compiler.v2_3.ExecutionMode;
|import org.neo4j.cypher.internal.compiler.v2_3.TaskCloser;
|import org.neo4j.cypher.internal.compiler.v2_3.birk.QueryExecutionTracer;
|import org.neo4j.cypher.internal.compiler.v2_3.birk.QueryExecutionEvent;
|import java.util.Map;
|
|$imports
Expand All @@ -137,12 +141,14 @@ object CodeGenerator {
|private final ReadOperations ro;
|private final GraphDatabaseService db;
|private final Map<String, Object> params;
|private final QueryExecutionTracer tracer;
|
|public $className( TaskCloser closer, Statement statement, GraphDatabaseService db, ExecutionMode executionMode, InternalPlanDescription description, Map<String, Object> params )
|public $className( TaskCloser closer, Statement statement, GraphDatabaseService db, ExecutionMode executionMode, Supplier<InternalPlanDescription> description, QueryExecutionTracer tracer, Map<String, Object> params )
|{
| super( closer, statement, executionMode, description );
| this.ro = statement.readOperations();
| this.db = db;
| this.tracer = tracer;
| this.params = params;
|}
|
Expand Down Expand Up @@ -199,8 +205,10 @@ class CodeGenerator {
val idMap = LogicalPlanIdentificationBuilder(plan)
val description: InternalPlanDescription = LogicalPlan2PlanDescription(plan, idMap)

val builder = (st: Statement, db: GraphDatabaseService, mode: ExecutionMode, params: Map[String, Any], closer: TaskCloser) =>
Javac.newInstance(clazz, closer, st, db, mode, description, asJavaHashMap(params))
val builder = (st: Statement, db: GraphDatabaseService, mode: ExecutionMode, tracing:(InternalPlanDescription=>(Supplier[InternalPlanDescription],Option[QueryExecutionTracer])), params: Map[String, Any], closer: TaskCloser) => {
val (supplier, tracer) = tracing(description)
Javac.newInstance(clazz, closer, st, db, mode, supplier, tracer.getOrElse(QueryExecutionTracer.NONE), asJavaHashMap(params))
}

val columns = res.nodes ++ res.relationships ++ res.other
CompiledPlan(updating = false, None, fp, GreedyPlannerName, description, columns, builder)
Expand Down
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2002-2015 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.neo4j.cypher.internal.compiler.v2_3.birk;

public interface QueryExecutionEvent extends AutoCloseable
{
void dbHit();

void row();

@Override
void close();

QueryExecutionEvent NONE = new QueryExecutionEvent()
{
@Override
public void dbHit()
{
}

@Override
public void row()
{
throw new UnsupportedOperationException( "not implemented" );
}

@Override
public void close()
{
}
};
}
Expand Up @@ -29,6 +29,7 @@ import org.neo4j.cypher.internal.compiler.v2_3.notification.InternalNotification
import org.neo4j.cypher.internal.compiler.v2_3.planDescription.InternalPlanDescription
import org.neo4j.cypher.internal.compiler.v2_3.planDescription.InternalPlanDescription.Arguments.{Runtime, Planner}
import org.neo4j.cypher.internal.compiler.v2_3.{ExecutionMode, ExplainMode, ProfileMode, _}
import org.neo4j.function.Supplier
import org.neo4j.graphdb.QueryExecutionType._
import org.neo4j.graphdb.Result.{ResultRow, ResultVisitor}
import org.neo4j.graphdb._
Expand All @@ -40,7 +41,7 @@ import scala.collection.{Map, mutable}
* Base class for compiled execution results, implements everything in InternalExecutionResult
* except `javaColumns` and `accept` which should be implemented by the generated classes.
*/
abstract class CompiledExecutionResult(taskCloser: TaskCloser, statement:Statement, executionMode:ExecutionMode, description:InternalPlanDescription) extends InternalExecutionResult {
abstract class CompiledExecutionResult(taskCloser: TaskCloser, statement:Statement, executionMode:ExecutionMode, description:Supplier[InternalPlanDescription]) extends InternalExecutionResult {
self =>

import scala.collection.JavaConverters._
Expand Down Expand Up @@ -118,7 +119,7 @@ abstract class CompiledExecutionResult(taskCloser: TaskCloser, statement:Stateme
taskCloser.close(success = successful)
}

override def executionPlanDescription() = description
override def executionPlanDescription() = description.get()

def mode = executionMode

Expand Down

0 comments on commit a24e5f2

Please sign in to comment.