Skip to content
This repository was archived by the owner on Jan 27, 2025. It is now read-only.

Commit c89ff05

Browse files
authored
Merge pull request #7 from liblaf/jni-interface-counter
add JNI Interface Counter
2 parents 2651be8 + b986697 commit c89ff05

30 files changed

+608
-48
lines changed

CMakeLists.txt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ endif()
44
project(clang-wrapper VERSION 0.6.0)
55
cmake_minimum_required(VERSION 3.24)
66

7-
include(cmake/config.cmake)
7+
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
8+
include(config)
89

910
aux_source_directory(${CMAKE_SOURCE_DIR}/src/common/ COMMON_SRCS)
1011
list(APPEND COMMON_SRCS src/utility/assertion.cc)
@@ -17,12 +18,26 @@ target_compile_definitions(base++ PUBLIC USE_CXX)
1718
list(APPEND CALL_HOOK_SRCS ${BASE_SRCS} src/pass/pass_call_hook.cc src/wrapper/wrapper_call_hook.cc)
1819
add_executable(call-hook ${CALL_HOOK_SRCS} src/main/call_hook.cc)
1920
add_executable(call-hook++ ${CALL_HOOK_SRCS} src/main/call_hook.cc)
20-
target_compile_definitions(call-hook PUBLIC RUNTIME_HOME="${CMAKE_SOURCE_DIR}/src/runtime/call_hook")
21-
target_compile_definitions(call-hook++ PUBLIC RUNTIME_HOME="${CMAKE_SOURCE_DIR}/src/runtime/call_hook")
21+
target_compile_definitions(call-hook PUBLIC RUNTIME_HOME="${CMAKE_SOURCE_DIR}/runtime/call_hook")
22+
target_compile_definitions(call-hook++ PUBLIC RUNTIME_HOME="${CMAKE_SOURCE_DIR}/runtime/call_hook")
2223
target_compile_definitions(call-hook++ PUBLIC USE_CXX)
2324

2425
list(APPEND STRUCT_PARSER_SRCS ${BASE_SRCS} src/pass/pass_struct_parser.cc src/wrapper/wrapper_struct_parser.cc src/utility/struct_parser.cc)
2526
list(APPEND STRUCT_PARSER_SRCS src/utility/location.cc)
2627
add_executable(struct-parser ${STRUCT_PARSER_SRCS} src/main/struct_parser.cc)
2728
add_executable(struct-parser++ ${STRUCT_PARSER_SRCS} src/main/struct_parser.cc)
2829
target_compile_definitions(struct-parser++ PUBLIC USE_CXX)
30+
31+
list(APPEND JNI_INTERFACE_COUNTER_SRCS ${CALL_HOOK_SRCS})
32+
list(APPEND JNI_INTERFACE_COUNTER_SRCS src/pass/jni/pass_interface_counter.cc)
33+
list(APPEND JNI_INTERFACE_COUNTER_SRCS src/utility/jni/jni_interface_detector.cc)
34+
list(APPEND JNI_INTERFACE_COUNTER_SRCS src/utility/location.cc)
35+
list(APPEND JNI_INTERFACE_COUNTER_SRCS src/utility/struct_parser.cc)
36+
list(APPEND JNI_INTERFACE_COUNTER_SRCS src/wrapper/jni/wrapper_interface_counter.cc)
37+
add_executable(jni-interface-counter ${JNI_INTERFACE_COUNTER_SRCS} src/main/jni/interface_counter.cc)
38+
add_executable(jni-interface-counter++ ${JNI_INTERFACE_COUNTER_SRCS} src/main/jni/interface_counter.cc)
39+
target_compile_definitions(jni-interface-counter PUBLIC HOOK_NAME="__before_interface_call")
40+
target_compile_definitions(jni-interface-counter++ PUBLIC HOOK_NAME="__before_interface_call")
41+
target_compile_definitions(jni-interface-counter PUBLIC RUNTIME_HOME="${CMAKE_SOURCE_DIR}/runtime/jni/interface_counter")
42+
target_compile_definitions(jni-interface-counter++ PUBLIC RUNTIME_HOME="${CMAKE_SOURCE_DIR}/runtime/jni/interface_counter")
43+
target_compile_definitions(jni-interface-counter++ PUBLIC USE_CXX)

cmake/config.cmake

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
include_guard()
2-
include(CMakePrintHelpers)
3-
include(cmake/utility.cmake)
2+
include(utility)
43

54
set(CMAKE_CXX_STANDARD 17)
65
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -71,3 +70,6 @@ add_compile_definitions(LOG_LEVEL=LOG_LEVEL_${LOG_LEVEL})
7170
add_compile_definitions(LOG_PATH="${LOG_PATH}")
7271
add_compile_definitions(TARGET_CC="${TARGET_CC}")
7372
add_compile_definitions(TARGET_CXX="${TARGET_CXX}")
73+
if(NDK)
74+
add_compile_definitions(NDK=1)
75+
endif()

runtime/common/dictionary.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "dictionary.h"
2+
3+
#include <stddef.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <time.h>
8+
9+
DEFINE_DICTIONARY(Dict, int, char);
10+
11+
int Dict_cmp(const DictKeyType* a, const DictKeyType* b) { return *a - *b; }
12+
13+
int Dict_hash(const DictKeyType* key) { return *key % 512; }
14+
15+
void Dict_key_copy(DictKeyType* dest, const DictKeyType* src) { *dest = *src; }
16+
17+
void Dict_value_copy(DictValueType* dest, const DictValueType* src) {
18+
*dest = *src;
19+
}
20+
21+
void test_dict(int n) {
22+
struct Dict* dict = Dict_new(n);
23+
for (int i = 0; i < (n / 2); ++i) {
24+
switch (rand() % 2) {
25+
case 0: { // get
26+
DictKeyType key = rand() % 10000;
27+
printf("Searching %d(%d): ", key, Dict_hash(&key));
28+
DictValueType* value = Dict_get(dict, key);
29+
if (value) {
30+
printf("Found with %c\n", *value);
31+
} else {
32+
printf("Not found\n");
33+
}
34+
break;
35+
}
36+
case 1: {
37+
DictKeyType key = rand() % 10000;
38+
DictValueType value = 'A' + (rand() % 26);
39+
printf("Inserting <%d(%d),%c>\n", key, Dict_hash(&key), value);
40+
Dict_put(dict, key, value);
41+
break;
42+
}
43+
default: {
44+
abort();
45+
}
46+
}
47+
}
48+
Dict_delete(dict);
49+
dict = NULL;
50+
}
51+
52+
int main(int argc, char** argv) {
53+
if (argc < 2) {
54+
printf("Usage: %s <size of test>\n", argv[0]);
55+
return 1;
56+
}
57+
srand((unsigned int)time(NULL));
58+
test_dict(atoi(argv[1]));
59+
return 0;
60+
}

runtime/common/dictionary.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#ifndef DICTIONARY_H_
2+
#define DICTIONARY_H_
3+
4+
#include <stdlib.h>
5+
6+
#define DEFINE_DICTIONARY(Name, _KeyType, _ValueType) \
7+
typedef _KeyType Name##KeyType; \
8+
typedef _ValueType Name##ValueType; \
9+
\
10+
struct Name##Entry { \
11+
Name##KeyType key; \
12+
Name##ValueType value; \
13+
}; \
14+
\
15+
struct Name { \
16+
struct Name##Entry** _buckets; \
17+
int _capacity; \
18+
int _size; \
19+
}; \
20+
\
21+
int Name##_cmp(const Name##KeyType* a, const Name##KeyType* b); \
22+
int Name##_hash(const Name##KeyType* key); \
23+
void Name##_key_copy(Name##KeyType* dest, const Name##KeyType* src); \
24+
void Name##_value_copy(Name##ValueType* dest, const Name##ValueType* src); \
25+
\
26+
struct Name* Name##_new(const int capacity); \
27+
void Name##_delete(struct Name* self); \
28+
int Name##_capacity(struct Name* self); \
29+
Name##ValueType* Name##_get(struct Name* self, const Name##KeyType key); \
30+
int Name##_hash(const Name##KeyType* key); \
31+
void Name##_put(struct Name* self, const Name##KeyType key, \
32+
const Name##ValueType value); \
33+
int Name##_size(struct Name* self); \
34+
\
35+
int _Name##_probe_for_free(struct Name* self, const Name##KeyType* key); \
36+
int _Name##_probe_for_hit(struct Name* self, const Name##KeyType* key); \
37+
\
38+
struct Name* Name##_new(const int capacity) { \
39+
struct Name* dict = (struct Name*)calloc(1, sizeof(struct Name)); \
40+
dict->_buckets = \
41+
(struct Name##Entry**)calloc(capacity, sizeof(struct Name##Entry*)); \
42+
dict->_capacity = capacity; \
43+
dict->_size = 0; \
44+
return dict; \
45+
} \
46+
\
47+
void Name##_delete(struct Name* self) { \
48+
for (int i = 0; i < self->_capacity; ++i) { \
49+
free(self->_buckets[i]); \
50+
} \
51+
free(self->_buckets); \
52+
free(self); \
53+
} \
54+
\
55+
int Name##_capacity(struct Name* self) { return self->_capacity; } \
56+
\
57+
Name##ValueType* Name##_get(struct Name* self, const Name##KeyType key) { \
58+
int i = _Name##_probe_for_hit(self, &key); \
59+
if (self->_buckets[i]) { \
60+
return &(self->_buckets[i]->value); \
61+
} else { \
62+
return NULL; \
63+
} \
64+
} \
65+
\
66+
void Name##_put(struct Name* self, const Name##KeyType key, \
67+
const Name##ValueType value) { \
68+
int i = _Name##_probe_for_hit(self, &key); \
69+
if (self->_buckets[i]) { \
70+
Name##_value_copy(&(self->_buckets[i]->value), &value); \
71+
} else { \
72+
i = _Name##_probe_for_free(self, &key); \
73+
self->_buckets[i] = \
74+
(struct Name##Entry*)calloc(1, sizeof(struct Name##Entry)); \
75+
Name##_key_copy(&(self->_buckets[i]->key), &key); \
76+
Name##_value_copy(&(self->_buckets[i]->value), &value); \
77+
++(self->_size); \
78+
} \
79+
} \
80+
\
81+
int Name##_size(struct Name* self) { return self->_size; } \
82+
\
83+
int _Name##_probe_for_free(struct Name* self, const Name##KeyType* key) { \
84+
int hash = Name##_hash(key); \
85+
int i = hash % (self->_capacity); \
86+
while (self->_buckets[i]) { \
87+
i = (i + 1) % (self->_capacity); \
88+
} \
89+
return i; \
90+
} \
91+
\
92+
int _Name##_probe_for_hit(struct Name* self, const Name##KeyType* key) { \
93+
int hash = Name##_hash(key); \
94+
int i = hash % (self->_capacity); \
95+
while (self->_buckets[i] && Name##_cmp(key, &(self->_buckets[i]->key))) { \
96+
i = (i + 1) % (self->_capacity); \
97+
} \
98+
return i; \
99+
}
100+
101+
#endif // DICTIONARY_H_
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include "declaration.h"
2+
3+
#include "runtime.h"
4+
5+
#ifndef NULL
6+
#define NULL 0
7+
#endif // NULL
8+
9+
void __foo() { __before_interface_call(NULL, NULL); }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef DECLARATION_H_
2+
#define DECLARATION_H_
3+
4+
void __foo();
5+
6+
#endif // DECLARATION_H_
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include "runtime.h"
2+
3+
#include <stddef.h>
4+
#include <stdio.h>
5+
#include <string.h>
6+
#include <time.h>
7+
8+
#include "../../common/dictionary.h"
9+
10+
#ifndef INTERFACE_COUNTER_PATH
11+
#define INTERFACE_COUNTER_PATH "/sdcard/interface-counter"
12+
#endif // INTERFACE_COUNTER_PATH
13+
14+
#ifndef FILENAME_CAPACITY
15+
#define FILENAME_CAPACITY 128
16+
#endif // FILENAME_CAPACITY
17+
18+
#ifndef SAVE_INTERVAL
19+
#define SAVE_INTERVAL 8
20+
#endif // SAVE_INTERVAL
21+
22+
#ifdef ANDROID
23+
#include <android/log.h>
24+
#define LOG_TAG "liblaf"
25+
#define ALOGV(...) \
26+
__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
27+
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
28+
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
29+
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
30+
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
31+
#define ALOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
32+
#else
33+
#define ALOGV(...)
34+
#define ALOGD(...)
35+
#define ALOGI(...)
36+
#define ALOGW(...)
37+
#define ALOGE(...)
38+
#define ALOGF(...)
39+
#endif
40+
41+
DEFINE_DICTIONARY(Dict, const char*, int);
42+
43+
static void save_to_file();
44+
static void __attribute__((constructor(100))) runtime_init();
45+
static void __attribute__((destructor(100))) runtime_exit();
46+
47+
static FILE* file = NULL;
48+
static struct Dict* dict = NULL;
49+
static int counter = 0;
50+
51+
int Dict_cmp(const DictKeyType* a, const DictKeyType* b) {
52+
return strcmp(*a, *b);
53+
}
54+
55+
int Dict_hash(const DictKeyType* key) {
56+
int hash = 0;
57+
for (size_t n = strlen(*key), i = 0; i < n; i++) {
58+
hash = (hash << 5) | (hash >> 27);
59+
hash += (*key)[i];
60+
hash &= 0x7fffffff;
61+
}
62+
return hash;
63+
}
64+
65+
void Dict_key_copy(DictKeyType* dest, const DictKeyType* src) { *dest = *src; }
66+
67+
void Dict_value_copy(DictValueType* dest, const DictValueType* src) {
68+
*dest = *src;
69+
}
70+
71+
void __before_interface_call(const char* loc, const char* called_func_name) {
72+
int* value = Dict_get(dict, called_func_name);
73+
if (value) {
74+
++(*value);
75+
} else {
76+
Dict_put(dict, called_func_name, 1);
77+
}
78+
if (++counter >= SAVE_INTERVAL) {
79+
save_to_file();
80+
counter = 0;
81+
}
82+
}
83+
84+
static void save_to_file() {
85+
rewind(file);
86+
for (int i = 0; i < Dict_capacity(dict); ++i) {
87+
if (dict->_buckets[i]) {
88+
fprintf(file, "%s %d\n", dict->_buckets[i]->key,
89+
dict->_buckets[i]->value);
90+
}
91+
}
92+
fflush(file);
93+
}
94+
95+
static void runtime_init() {
96+
if (dict || file) return;
97+
dict = Dict_new(1000009);
98+
char filename[FILENAME_CAPACITY];
99+
sprintf(filename, "%s/%09ld.txt", INTERFACE_COUNTER_PATH, clock());
100+
file = fopen(filename, "w");
101+
ALOGI("runtime_init(%s)", filename);
102+
}
103+
104+
static void runtime_exit() {
105+
ALOGI("runtime_exit()");
106+
save_to_file();
107+
fclose(file);
108+
Dict_delete(dict);
109+
dict = NULL;
110+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef RUNTIME_H_
2+
#define RUNTIME_H_
3+
4+
void __before_interface_call(const char* loc, const char* called_func_name);
5+
6+
#endif // RUNTIME_H_

scripts/log.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
set -o errexit
3+
set -o nounset
4+
5+
sub_command="${1:-"purge"}"
6+
shift 1
7+
if [[ -n "${2:-""}" ]]; then
8+
path="${2}"
9+
else
10+
WRAPPER_HOME="$(dirname "$(dirname "$(realpath "${0}")")")"
11+
path="${WRAPPER_HOME}/build/log/"
12+
fi
13+
case "${sub_command}" in
14+
"remove")
15+
ls "${path}"
16+
rm --recursive "${path}"
17+
mkdir --parents "${path}"
18+
;;
19+
"purge")
20+
fd --no-ignore --size -64B . "${path}"
21+
fd --no-ignore --size -64B . "${path}" --exec rm
22+
;;
23+
esac

0 commit comments

Comments
 (0)