Skip to content

Commit 6117ab5

Browse files
committed
[Self-profiler revamp 2/2]: Profile generator.
The runtime component of the profiler is separated into its own crate. This crate defines a strongy typed representation of debugging information associated with each DDlog operator, which includes operator kind (arrange, join, flatmap, etc), relations and arrangements that the operator takes as inputs, and the source code location of the operator. The crate also implements methods to convert profiling information accumulated at runtime along with debug info associate with each operator to JSON and to dump this JSON into and HTML document. The compiler has been modified to inject debug info into the generated dataflow program. As the DDlog runtime instantiates the dataflow graph, it initializes the profiler with a mapping between DD operators and DDlog debug info. In addition, the compiler injects a copy of the program source code into the generated Rust program. At runtime the profiler dumps this code in the `src` folder in the profiling directory on the first call to `dump_profile`. Signed-off-by: Leonid Ryzhyk <[email protected]>
1 parent f1b04ae commit 6117ab5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+4547
-1121
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"rust/template/ovsdb",
55
"rust/template/cmd_parser",
66
"rust/template/ddlog_derive",
7+
"rust/template/ddlog_profiler",
78
"rust/template/differential_datalog",
89
"rust/template/differential_datalog_test",
910
]

app/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ parseValidate :: (?cfg::Config) => IO ([DatalogModule], DatalogProgram, M.Map Mo
191191
parseValidate = do
192192
let Config{..} = ?cfg
193193
fdata <- readFile confDatalogFile
194-
parsed <- runExceptT $ parseDatalogProgram (takeDirectory confDatalogFile:confLibDirs) True fdata confDatalogFile
194+
parsed <- runExceptT $ parseDatalogProgram (takeDirectory confDatalogFile:confLibDirs) True fdata confDatalogFile False
195195
(modules, d, rs_code) <- case parsed of
196196
Left e -> compilerError e
197197
Right res -> return res

java/ddlogapi.c

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,9 +714,73 @@ JNIEXPORT void JNICALL Java_ddlogapi_DDlogAPI_query_1index(
714714
free(cbinfo);
715715
}
716716

717-
JNIEXPORT jstring JNICALL Java_ddlogapi_DDlogAPI_ddlog_1profile(
717+
JNIEXPORT jstring JNICALL Java_ddlogapi_DDlogAPI_ddlog_1dump_1profile(
718+
JNIEnv *env, jobject obj, jlong progHandle, jstring label) {
719+
const char* label_str = NULL;
720+
if (label != NULL) {
721+
label_str = (*env)->GetStringUTFChars(env, label, NULL);
722+
}
723+
char* filename = ddlog_dump_profile((ddlog_prog)progHandle, label_str);
724+
if (label != NULL) {
725+
(*env)->ReleaseStringUTFChars(env, label, label_str);
726+
}
727+
728+
if (filename == NULL) {
729+
throwDDlogException(env, NULL);
730+
return NULL;
731+
};
732+
jstring result = (*env)->NewStringUTF(env, filename);
733+
ddlog_string_free(filename);
734+
return result;
735+
}
736+
737+
JNIEXPORT jstring JNICALL Java_ddlogapi_DDlogAPI_ddlog_1arrangement_1size_1profile(
738+
JNIEnv *env, jobject obj, jlong progHandle) {
739+
char* profile = ddlog_arrangement_size_profile((ddlog_prog)progHandle);
740+
741+
if (profile == NULL) {
742+
throwDDlogException(env, NULL);
743+
return NULL;
744+
};
745+
jstring result = (*env)->NewStringUTF(env, profile);
746+
ddlog_string_free(profile);
747+
return result;
748+
}
749+
750+
JNIEXPORT jstring JNICALL Java_ddlogapi_DDlogAPI_ddlog_1peak_1arrangement_1size_1profile(
718751
JNIEnv *env, jobject obj, jlong progHandle) {
719-
char* profile = ddlog_profile((ddlog_prog)progHandle);
752+
char* profile = ddlog_peak_arrangement_size_profile((ddlog_prog)progHandle);
753+
754+
if (profile == NULL) {
755+
throwDDlogException(env, NULL);
756+
return NULL;
757+
};
758+
jstring result = (*env)->NewStringUTF(env, profile);
759+
ddlog_string_free(profile);
760+
return result;
761+
}
762+
763+
JNIEXPORT jstring JNICALL Java_ddlogapi_DDlogAPI_ddlog_1change_1profile(
764+
JNIEnv *env, jobject obj, jlong progHandle) {
765+
char* profile = ddlog_change_profile((ddlog_prog)progHandle);
766+
767+
if (profile == NULL) {
768+
throwDDlogException(env, NULL);
769+
return NULL;
770+
};
771+
jstring result = (*env)->NewStringUTF(env, profile);
772+
ddlog_string_free(profile);
773+
return result;
774+
}
775+
776+
JNIEXPORT jstring JNICALL Java_ddlogapi_DDlogAPI_ddlog_1cpu_1profile(
777+
JNIEnv *env, jobject obj, jlong progHandle) {
778+
char* profile = ddlog_cpu_profile((ddlog_prog)progHandle);
779+
780+
if (profile == NULL) {
781+
throwDDlogException(env, NULL);
782+
return NULL;
783+
};
720784
jstring result = (*env)->NewStringUTF(env, profile);
721785
ddlog_string_free(profile);
722786
return result;

java/ddlogapi/DDlogAPI.java

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ native long ddlog_run_with_config(
5454
static native void ddlog_query_index_from_flatbuf(long hprog, byte[] bytes, int position, FlatBufDescr fb) throws DDlogException;
5555
static native void ddlog_dump_index_to_flatbuf(long hprog, long idxid, FlatBufDescr fb) throws DDlogException;
5656
static native int ddlog_clear_relation(long hprog, int relid);
57-
static native String ddlog_profile(long hprog);
57+
static native String ddlog_dump_profile(long hprog, String label);
58+
static native String ddlog_arrangement_size_profile(long hprog);
59+
static native String ddlog_peak_arrangement_size_profile(long hprog);
60+
static native String ddlog_change_profile(long hprog);
61+
static native String ddlog_cpu_profile(long hprog);
5862
static native void ddlog_enable_cpu_profiling(long hprog, boolean enable) throws DDlogException;
5963
static native void ddlog_enable_change_profiling(long hprog, boolean enable) throws DDlogException;
6064
static native long ddlog_log_replace_callback(int module, long old_cbinfo, ObjIntConsumer<String> cb, int max_level);
@@ -649,13 +653,65 @@ public void queryIndex(String index, DDlogRecord key, Consumer<DDlogRecord> call
649653
}
650654

651655
/**
652-
* Returns DDlog program runtime profile as a string.
656+
* Dump DDlog program runtime profile to a file;
657+
* returns the name of the file.
653658
*
654-
* See <code>ddlog.h: ddlog_profile()</code>
659+
* See <code>ddlog.h: ddlog_dump_profile()</code>
655660
*/
656-
public String profile() throws DDlogException {
661+
public String dumpProfile() throws DDlogException {
657662
this.checkHandle();
658-
return DDlogAPI.ddlog_profile(this.hprog);
663+
return DDlogAPI.ddlog_dump_profile(this.hprog, null);
664+
}
665+
666+
/**
667+
* Dump DDlog program runtime profile to a file; include <code>label</code>
668+
* in the filename; returns the name of the file.
669+
*
670+
* See <code>ddlog.h: ddlog_dump_profile()</code>
671+
*/
672+
public String dumpProfile(String label) throws DDlogException {
673+
this.checkHandle();
674+
return DDlogAPI.ddlog_dump_profile(this.hprog, label);
675+
}
676+
677+
/**
678+
* Returns DDlog arrangement size profile as a JSON string.
679+
*
680+
* See <code>ddlog.h: ddlog_arrangement_size_profile()</code>
681+
*/
682+
public String arrangementSizeProfile() throws DDlogException {
683+
this.checkHandle();
684+
return DDlogAPI.ddlog_arrangement_size_profile(this.hprog);
685+
}
686+
687+
/**
688+
* Returns DDlog peak arrangement size profile as a JSON string.
689+
*
690+
* See <code>ddlog.h: ddlog_arrangement_size_profile()</code>
691+
*/
692+
public String peakArrangementSizeProfile() throws DDlogException {
693+
this.checkHandle();
694+
return DDlogAPI.ddlog_peak_arrangement_size_profile(this.hprog);
695+
}
696+
697+
/**
698+
* Returns DDlog arrangement change profile as a JSON string.
699+
*
700+
* See <code>ddlog.h: ddlog_change_profile()</code>
701+
*/
702+
public String changeProfile() throws DDlogException {
703+
this.checkHandle();
704+
return DDlogAPI.ddlog_change_profile(this.hprog);
705+
}
706+
707+
/**
708+
* Returns DDlog CPU profile as a JSON string.
709+
*
710+
* See <code>ddlog.h: ddlog_cpu_profile()</code>
711+
*/
712+
public String cpuProfile() throws DDlogException {
713+
this.checkHandle();
714+
return DDlogAPI.ddlog_cpu_profile(this.hprog);
659715
}
660716

661717
/**

java/test/SpanTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,7 @@ void parseLine(String line)
382382
this.api.enableCpuProfiling(false);
383383
break;
384384
case "":
385-
String profile = this.api.profile();
386-
System.out.println("Profile:");
385+
String profile = this.api.dumpProfile();
387386
System.out.println(profile);
388387
this.checkSemicolon();
389388
break;

java/test1/RedistTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,9 +450,8 @@ void parseLine(String line)
450450
this.api.enableCpuProfiling(false);
451451
break;
452452
case "":
453-
String profile = this.api.profile();
454-
System.out.println("Profile:");
455-
System.out.println(profile);
453+
String prof_file = this.api.dumpProfile();
454+
System.out.println(prof_file);
456455
this.checkSemicolon();
457456
break;
458457
default:

java/test_flatbuf1/Test.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
import java.util.Arrays;
1414
import java.io.PrintStream;
1515
import java.io.UncheckedIOException;
16+
import java.nio.file.Files;
17+
import java.nio.file.Paths;
1618

1719
/* Generic DDlog API shared by all programs. */
1820
import ddlogapi.DDlogAPI;
21+
import ddlogapi.DDlogConfig;
1922
import ddlogapi.DDlogCommand;
2023
import ddlogapi.DDlogRecCommand;
2124
import ddlogapi.DDlogRecord;
@@ -32,7 +35,9 @@ public class Test {
3235

3336
Test() throws IOException, DDlogException {
3437
/* Create an instance of the DDlog program with one worker thread. */
35-
this.api = new DDlogAPI(1, false);
38+
this.api = new DDlogAPI(new DDlogConfig(1, false, 0, DDlogConfig.selfProfiling()), false);
39+
api.enableCpuProfiling(true);
40+
api.enableChangeProfiling(true);
3641
api.recordCommands("replay.dat", false);
3742

3843
this.fb_file = new PrintStream("fb.dump");
@@ -1824,6 +1829,22 @@ void run() throws IOException, DDlogException {
18241829

18251830
this.fb_file.close();
18261831
this.query_file.close();
1832+
1833+
String profile_fname = this.api.dumpProfile();
1834+
System.out.println("Profile written to '" + profile_fname + "'");
1835+
String size_profile = this.api.arrangementSizeProfile();
1836+
Files.write(Paths.get("arrangement_size_profile.json"), size_profile.getBytes());
1837+
System.out.println("Arrangement size profile written to 'arrangement_size_profile.json'");
1838+
String peak_profile = this.api.peakArrangementSizeProfile();
1839+
Files.write(Paths.get("peak_arrangement_size_profile.json"), peak_profile.getBytes());
1840+
System.out.println("Peak arrangement size profile written to 'peak_arrangement_size_profile.json'");
1841+
String change_profile = this.api.changeProfile();
1842+
Files.write(Paths.get("change_profile.json"), change_profile.getBytes());
1843+
System.out.println("Change profile written to 'change_profile.json'");
1844+
String cpu_profile = this.api.cpuProfile();
1845+
Files.write(Paths.get("cpu_profile.json"), cpu_profile.getBytes());
1846+
System.out.println("CPU profile written to 'cpu_profile.json'");
1847+
18271848
}
18281849

18291850
public static void main(String[] args) throws IOException, DDlogException {

package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ dependencies:
4343
- githash
4444
- process
4545
- aeson
46+
- utf8-string
4647

4748
library:
4849
source-dirs: src

rust/template/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ differential-dataflow = { git = "https://github.com/ddlog-dev/differential-dataf
2424
#timely = "0.11"
2525
timely = { git = "https://github.com/ddlog-dev/timely-dataflow", branch = "ddlog-4", default-features = false }
2626
fnv = "1.0.2"
27-
once_cell = "1.4.1"
27+
once_cell = "1.8.0"
2828
libc = "0.2"
2929
num-traits = "0.2"
3030
num = { version = "0.3", features = ["serde"] }
@@ -44,6 +44,9 @@ flatbuffers = { version = "2.0.0", optional = true }
4444
[dependencies.differential_datalog]
4545
path = "./differential_datalog"
4646

47+
[dependencies.ddlog_profiler]
48+
path = "./ddlog_profiler"
49+
4750
[dependencies.cmd_parser]
4851
path = "./cmd_parser"
4952
optional = true

rust/template/ddlog.h

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,19 @@ typedef struct {
147147
typedef struct {
148148
ddlog_profiling_mode mode;
149149

150+
/* The following fields are only used if (mode == ddlog_self_profiling) */
151+
152+
// Directory to store self-profiler output. Set to NULL to use current
153+
// working directory.
154+
const char *self_profiler_dir;
155+
150156
/* The following fields are only used if (mode == ddlog_timely_profiling) */
151157

152158
// Destination for the timely log stream.
153159
ddlog_log_destination timely_destination;
154160
// Destination for timely progress logging.
155161
ddlog_log_destination timely_progress_destination;
156-
// Differential for Differential Dataflow events.
162+
// Destination for Differential Dataflow events.
157163
ddlog_log_destination differential_destination;
158164
} ddlog_profiling_config;
159165

@@ -815,13 +821,6 @@ extern int ddlog_enable_cpu_profiling(ddlog_prog prog, bool enable);
815821
*/
816822
extern int ddlog_enable_change_profiling(ddlog_prog prog, bool enable);
817823

818-
/*
819-
* Returns DDlog program runtime profile as a C string.
820-
*
821-
* The returned string must be deallocated using `ddlog_string_free()`.
822-
*/
823-
extern char* ddlog_profile(ddlog_prog prog);
824-
825824
/*
826825
* Controls recording of timely operator runtimes. When enabled,
827826
* DDlog receives timely dataflow events and writes them out to a CSV file
@@ -835,6 +834,65 @@ extern char* ddlog_profile(ddlog_prog prog);
835834
*/
836835
extern int ddlog_enable_timely_profiling(ddlog_prog prog, bool enable);
837836

837+
/*
838+
* Dumps DDlog program runtime profile to a file. `label` is an optional
839+
* label used, along with the current time, to generate a file name to
840+
* store the profile. Set `label` to `NULL`
841+
*
842+
* Returns absolute path to the generated HTML profile file. All profiles
843+
* for a process (even if the process runs multiple DDlog instances) will
844+
* be stored in the same directory.
845+
*
846+
* The returned string must be deallocated using `ddlog_string_free()`.
847+
*/
848+
extern char* ddlog_dump_profile(ddlog_prog prog, const char *label);
849+
850+
/*
851+
* Returns arrangement size profile as a JSON string.
852+
*
853+
* The returned string must be deallocated using `ddlog_string_free()`.
854+
*
855+
* Fails if the program runs with self-profiler disabled.
856+
* Returns `NULL` on error.
857+
*/
858+
extern char* ddlog_arrangement_size_profile(ddlog_prog prog);
859+
860+
/*
861+
* Returns peak arrangement size profile as a JSON string.
862+
*
863+
* The returned string must be deallocated using `ddlog_string_free()`.
864+
*
865+
* Fails if the program runs with self-profiler disabled.
866+
* Returns `NULL` on error.
867+
*/
868+
extern char* ddlog_peak_arrangement_size_profile(ddlog_prog prog);
869+
870+
/*
871+
* Returns arrangement change profile as a JSON string. The
872+
* change profile can be empty if change profiling was never
873+
* enabled (using `ddlog_enable_change_profiling()`). In this
874+
* case, the function returns an empty JSON array (`[]`).
875+
*
876+
* The returned string must be deallocated using `ddlog_string_free()`.
877+
*
878+
* Fails if the program runs with self-profiler disabled.
879+
* Returns `NULL` on error.
880+
*/
881+
extern char* ddlog_change_profile(ddlog_prog prog);
882+
883+
/*
884+
* Returns DDlog's CPU profile as a JSON string. The CPU
885+
* profile can be empty if CPU profiling was never
886+
* enabled (using `ddlog_enable_cpu_profiling()`). In this
887+
* case, the function returns an empty JSON array (`[]`).
888+
*
889+
* The returned string must be deallocated using `ddlog_string_free()`.
890+
*
891+
* Fails if the program runs with self-profiler disabled.
892+
* On error, returns `NULL`.
893+
*/
894+
extern char* ddlog_cpu_profile(ddlog_prog prog);
895+
838896
/***********************************************************************
839897
* Record API
840898
***********************************************************************/
@@ -918,7 +976,7 @@ extern void ddlog_free(ddlog_record *rec);
918976

919977
/*
920978
* Deallocate a C string returned by DDlog
921-
* (currently only applicable to the string returned by `ddlog_profile()` and
979+
* (currently only applicable to the string returned by `ddlog_dump_profile()` and
922980
* `ddlog_dump_record()`).
923981
*/
924982
extern void ddlog_string_free(char *s);

0 commit comments

Comments
 (0)