Commit 37864d58 authored by Lukáš Marek's avatar Lukáš Marek

Added new dispatch2 tests - simple performance benchmark

disptach test uses new API
Exclusion set contains DiSL-RE classes

REDispatch
 - added method registration
 - removed session id

ClassInfo
 - separate class info for common, primitive and array types - needs more work
 - uses interfaces

Added parallel processing of analysis events

c-agent
 - net reference handling extracted to separate .h file - no lock usage
 - added analysis registration message
 - added one obj-tagging thread and one sending thread communicating through blocking synch. queues
 - analysis requests are send in batches
parent 6b7294f1
......@@ -25,7 +25,7 @@ LINK_SHARED=$(LINK.c) -shared -o $@
# GNU Compiler options needed to build it
COMMON_FLAGS=-fPIC
# Options that help find errors
COMMON_FLAGS+= -W -Wall -Wextra -O3 -Wno-unused-parameter
COMMON_FLAGS+= -W -Wall -Wextra -O3 -Wno-unused-parameter -lpthread
CFLAGS += $(COMMON_FLAGS)
......
#ifndef _BLOCKINGQUEUE_H
#define _BLOCKINGQUEUE_H
#include <string.h>
#include <pthread.h>
#include <jvmti.h>
#include <jni.h>
#include "../src-agent-c/jvmtihelper.h"
typedef struct {
// array of elements
char * qarray;
size_t qa_size;
size_t qa_element_size;
size_t first;
size_t occupied;
pthread_mutex_t mutex;
pthread_cond_t cond;
jvmtiEnv * jvmti;
} blocking_queue;
// ** Monitor helper functions **
static void _bq_monitor_enter(blocking_queue * bq) {
pthread_mutex_lock(&(bq->mutex));
}
static void _bq_monitor_exit(blocking_queue * bq) {
pthread_mutex_unlock(&(bq->mutex));
}
static void _bq_monitor_wait(blocking_queue * bq) {
pthread_cond_wait(&(bq->cond), &(bq->mutex));
}
static void _bq_monitor_notify_all(blocking_queue * bq) {
pthread_cond_broadcast(&(bq->cond));
}
// ** Blocking queue functions **
void bq_create(jvmtiEnv *jvmti, blocking_queue * bq, size_t queue_capacity,
size_t queue_element_size) {
check_std_error((bq == NULL), TRUE, "Invalid blocking queue structure");
bq->qarray = malloc(queue_capacity * queue_element_size);
bq->qa_size = queue_capacity;
bq->qa_element_size = queue_element_size;
bq->first = 0;
bq->occupied = 0;
// create lock and cond
int pci = pthread_cond_init(&(bq->cond), NULL);
check_std_error((pci != 0), TRUE, "Cannot create pthread condition");
int pmi = pthread_mutex_init(&(bq->mutex), NULL);
check_std_error((pmi != 0), TRUE, "Cannot create pthread mutex");
bq->jvmti = jvmti;
}
void bq_term (blocking_queue * bq) {
_bq_monitor_enter(bq); {
// delete array
free(bq->qarray);
bq->qarray = NULL;
}
_bq_monitor_exit(bq);
// destroy lock and cond
pthread_mutex_destroy(&(bq->mutex));
pthread_cond_destroy(&(bq->cond));
}
void bq_push(blocking_queue * bq, void * data) {
_bq_monitor_enter(bq); {
// wait for some empty space
while(bq->occupied == bq->qa_size) {
_bq_monitor_wait(bq);
}
// add data
size_t last = (bq->first + bq->occupied) % bq->qa_size;
size_t last_pos = last * bq->qa_element_size;
memcpy(&((bq->qarray)[last_pos]), data, bq->qa_element_size);
++(bq->occupied);
// notify
_bq_monitor_notify_all(bq);
}
_bq_monitor_exit(bq);
}
void bq_pop(blocking_queue * bq, void * empty) {
_bq_monitor_enter(bq); {
// wait for some item
while(bq->occupied == 0) {
_bq_monitor_wait(bq);
}
// get the data
size_t first_pos = bq->first * bq->qa_element_size;
memcpy(empty, &((bq->qarray)[first_pos]), bq->qa_element_size);
// insert 0 - better problem detection
memset(&((bq->qarray)[first_pos]), 0, bq->qa_element_size);
bq->first = (bq->first + 1) % bq->qa_size;
--(bq->occupied);
// notify
_bq_monitor_notify_all(bq);
}
_bq_monitor_exit(bq);
}
size_t bq_length(blocking_queue * bq) {
size_t length = 0;
_bq_monitor_enter(bq); {
length = bq->occupied;
}
_bq_monitor_exit(bq);
return length;
}
#endif /* _BLOCKINGQUEUE_H */
......@@ -8,8 +8,6 @@
// initial buffer size
static const size_t INIT_BUFF_SIZE = 512;
// max limit buffer size
static const size_t MAX_BUFF_SIZE = 8192;
typedef struct {
unsigned char * buff;
......@@ -62,16 +60,28 @@ void buffer_fill(buffer * b, const void * data, size_t data_length) {
b->occupied += data_length;
}
void buffer_clean(buffer * b) {
// if capacity is higher then limit "reset" buffer
// should keep memory consumption in limits
if(b->capacity > MAX_BUFF_SIZE) {
// the space has to be already filled with data - no extensions
void buffer_fill_at_pos(buffer * b, size_t pos, const void * data,
size_t data_length) {
buffer_free(b);
buffer_alloc(b);
// space is not filled already - error
if(b->occupied < pos + data_length) {
check_error(TRUE, "Filling buffer at non-occupied position.");
}
memcpy(b->buff + pos, data, data_length);
}
void buffer_read(buffer * b, size_t pos, void * data, size_t data_length) {
memcpy(data, b->buff + pos, data_length);
}
size_t buffer_filled(buffer * b) {
return b->occupied;
}
void buffer_clean(buffer * b) {
b->occupied = 0;
}
......
This diff is collapsed.
......@@ -14,107 +14,115 @@ extern "C" {
#endif
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: analysisStart
* Signature: (Ljava/lang/String;)I
* Method: registerMethod
* Signature: (Ljava/lang/String;)S
*/
JNIEXPORT jint JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisStart
JNIEXPORT jshort JNICALL Java_ch_usi_dag_dislre_REDispatch_registerMethod
(JNIEnv *, jclass, jstring);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: analysisStart
* Signature: (S)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisStart
(JNIEnv *, jclass, jshort);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: analysisEnd
* Signature: (I)V
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisEnd
(JNIEnv *, jclass, jint);
(JNIEnv *, jclass);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendBoolean
* Signature: (IZ)V
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendBoolean
(JNIEnv *, jclass, jint, jboolean);
(JNIEnv *, jclass, jboolean);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendByte
* Signature: (IB)V
* Signature: (B)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendByte
(JNIEnv *, jclass, jint, jbyte);
(JNIEnv *, jclass, jbyte);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendChar
* Signature: (IC)V
* Signature: (C)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendChar
(JNIEnv *, jclass, jint, jchar);
(JNIEnv *, jclass, jchar);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendShort
* Signature: (IS)V
* Signature: (S)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendShort
(JNIEnv *, jclass, jint, jshort);
(JNIEnv *, jclass, jshort);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendInt
* Signature: (II)V
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendInt
(JNIEnv *, jclass, jint, jint);
(JNIEnv *, jclass, jint);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendLong
* Signature: (IJ)V
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendLong
(JNIEnv *, jclass, jint, jlong);
(JNIEnv *, jclass, jlong);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendFloatAsInt
* Signature: (II)V
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendFloatAsInt
(JNIEnv *, jclass, jint, jint);
(JNIEnv *, jclass, jint);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendDoubleAsLong
* Signature: (IJ)V
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendDoubleAsLong
(JNIEnv *, jclass, jint, jlong);
(JNIEnv *, jclass, jlong);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendString
* Signature: (ILjava/lang/String;)V
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendString
(JNIEnv *, jclass, jint, jstring);
(JNIEnv *, jclass, jstring);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendObject
* Signature: (ILjava/lang/Object;)V
* Signature: (Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendObject
(JNIEnv *, jclass, jint, jobject);
(JNIEnv *, jclass, jobject);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendClass
* Signature: (ILjava/lang/Class;)V
* Signature: (Ljava/lang/Class;)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendClass
(JNIEnv *, jclass, jint, jclass);
(JNIEnv *, jclass, jclass);
#ifdef __cplusplus
}
......
......@@ -5,16 +5,18 @@
// - should be in sync with java server
// closing connection
static const jint MSG_CLOSE = 0;
static const jbyte MSG_CLOSE = 0;
// sending analysis
static const jint MSG_ANALYZE = 1;
static const jbyte MSG_ANALYZE = 1;
// sending object free
static const jint MSG_OBJ_FREE = 2;
static const jbyte MSG_OBJ_FREE = 2;
// sending new class
static const jint MSG_NEW_CLASS = 3;
static const jbyte MSG_NEW_CLASS = 3;
// sending class info
static const jint MSG_CLASS_INFO = 4;
// sending class info
static const jint MSG_NEW_STRING = 5;
static const jbyte MSG_CLASS_INFO = 4;
// sending new string
static const jbyte MSG_NEW_STRING = 5;
// sending registration for analysis method
static const jbyte MSG_REG_ANALYSIS = 6;
#endif /* _MESSAGETYPE_H */
#ifndef _NETREF_H
#define _NETREF_H
#include <stdint.h>
#include <jvmti.h>
#include <jni.h>
#include "../src-agent-c/jvmtihelper.h"
#include "buffer.h"
#include "buffpack.h"
#include "messagetype.h"
// first available object id
static volatile jlong avail_object_id;
// first available class id
static volatile jint avail_class_id;
// ******************* Net reference get/set routines *******************
// should be in sync with NetReference on the server
// format of net reference looks like this
// HIGHEST (1 bit spec, 23 bits class id, 40 bits object id)
// bit field not used because there is no guarantee of alignment
static const uint8_t OBJECT_ID_POS = 0;
static const uint8_t CLASS_ID_POS = 40;
static const uint8_t SPEC_POS = 63;
static const uint64_t OBJECT_ID_MASK = 0xFFFFFFFFFFL;
static const uint64_t CLASS_ID_MASK = 0x7FFFFF;
static const uint64_t SPEC_MASK = 0x1;
// get bits from "from" with pattern "bit_mask" lowest bit starting on position
// "low_start" (from 0)
static inline uint64_t get_bits(uint64_t from, uint64_t bit_mask,
uint8_t low_start) {
// shift it
uint64_t bits_shifted = from >> low_start;
// mask it
return bits_shifted & bit_mask;
}
// set bits "bits" to "to" with pattern "bit_mask" lowest bit starting on
// position "low_start" (from 0)
static inline void set_bits(uint64_t * to, uint64_t bits,
uint64_t bit_mask, uint8_t low_start) {
// mask it
uint64_t bits_len = bits & bit_mask;
// move it to position
uint64_t bits_pos = bits_len << low_start;
// set
*to |= bits_pos;
}
inline jlong net_ref_get_object_id(jlong net_ref) {
return get_bits(net_ref, OBJECT_ID_MASK, OBJECT_ID_POS);
}
inline jint net_ref_get_class_id(jlong net_ref) {
return get_bits(net_ref, CLASS_ID_MASK, CLASS_ID_POS);
}
inline unsigned char net_ref_get_spec(jlong net_ref) {
return get_bits(net_ref, SPEC_MASK, SPEC_POS);
}
inline void net_ref_set_object_id(jlong * net_ref, jlong object_id) {
set_bits((uint64_t *)net_ref, object_id, OBJECT_ID_MASK, OBJECT_ID_POS);
}
inline void net_ref_set_class_id(jlong * net_ref, jint class_id) {
set_bits((uint64_t *)net_ref, class_id, CLASS_ID_MASK, CLASS_ID_POS);
}
inline void net_ref_set_spec(jlong * net_ref, unsigned char spec) {
set_bits((uint64_t *)net_ref, spec, SPEC_MASK, SPEC_POS);
}
// ******************* Net reference routines *******************
// TODO comment
// only retrieves object tag data
jlong get_tag(jvmtiEnv * jvmti_env, jobject obj) {
jlong net_ref;
jvmtiError error = (*jvmti_env)->GetTag(jvmti_env, obj, &net_ref);
check_jvmti_error(jvmti_env, error, "Cannot get object tag");
return net_ref;
}
// forward declaration
jlong get_net_reference(JNIEnv * jni_env, jvmtiEnv * jvmti_env,
buffer * new_obj_buff, jobject obj);
// !!! returned local reference should be freed
static jclass _get_class_for_object(JNIEnv * jni_env, jobject obj) {
return (*jni_env)->GetObjectClass(jni_env, obj);
}
static int _object_is_class(jvmtiEnv * jvmti_env, jobject obj) {
// TODO isn't there better way?
jvmtiError error =
(*jvmti_env)->GetClassSignature(jvmti_env, obj, NULL, NULL);
if(error != JVMTI_ERROR_NONE) {
// object is not class
return FALSE;
}
return TRUE;
}
// does not increment any counter - just sets the values
static jlong _set_net_reference(jvmtiEnv * jvmti_env, jobject obj,
jlong object_id, jint class_id, unsigned char spec) {
jlong net_ref = 0;
net_ref_set_object_id(&net_ref, object_id);
net_ref_set_class_id(&net_ref, class_id);
net_ref_set_spec(&net_ref, spec);
jvmtiError error = (*jvmti_env)->SetTag(jvmti_env, obj, net_ref);
check_jvmti_error(jvmti_env, error, "Cannot set object tag");
return net_ref;
}
static void _pack_class_info(buffer * buff, jlong class_net_ref,
char * class_sig, char * class_gen, jlong class_loader_net_ref,
jlong super_class_net_ref) {
// class gen can be NULL, we have to handle it
if(class_gen == NULL) {
class_gen = ""; // pack empty string
}
// pack class info message
// msg id
pack_byte(buff, MSG_CLASS_INFO);
// class id
pack_int(buff, net_ref_get_class_id(class_net_ref));
// class signature
pack_string_utf8(buff, class_sig, strlen(class_sig));
// class generic string
pack_string_utf8(buff, class_gen, strlen(class_gen));
// class loader id
pack_long(buff, class_loader_net_ref);
// super class id
pack_int(buff, net_ref_get_class_id(super_class_net_ref));
}
static jlong _set_net_reference_for_class(JNIEnv * jni_env,
jvmtiEnv * jvmti_env, buffer * buff, jclass klass) {
// manage references
// http://docs.oracle.com/javase/6/docs/platform/jvmti/jvmti.html#refs
static const jint ADD_REFS = 16;
jint res = (*jni_env)->PushLocalFrame(jni_env, ADD_REFS);
check_error(res != 0, "Cannot allocate more references");
// *** set net reference for class ***
// assign new net reference - set spec to 1 (binding send over network)
jlong net_ref = _set_net_reference(jvmti_env, klass,
avail_object_id, avail_class_id, 1);
// increment object id counter
++avail_object_id;
// increment class id counter
++avail_class_id;
// *** pack class info into buffer ***
jvmtiError error;
// resolve descriptor + generic
char * class_sig;
char * class_gen;
error = (*jvmti_env)->GetClassSignature(jvmti_env, klass, &class_sig,
&class_gen);
check_jvmti_error(jvmti_env, error, "Cannot get class signature");
// resolve class loader...
jobject class_loader;
error = (*jvmti_env)->GetClassLoader(jvmti_env, klass, &class_loader);
check_jvmti_error(jvmti_env, error, "Cannot get class loader");
// ... + class loader id
jlong class_loader_net_ref =
get_net_reference(jni_env, jvmti_env, buff, class_loader);
// resolve super class...
jclass super_class = (*jni_env)->GetSuperclass(jni_env, klass);
// ... + super class id
jlong super_class_net_ref =
get_net_reference(jni_env, jvmti_env, buff, super_class);
// pack class info into buffer
_pack_class_info(buff, net_ref, class_sig, class_gen, class_loader_net_ref,
super_class_net_ref);
// deallocate memory
error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)class_sig);
check_jvmti_error(jvmti_env, error, "Cannot deallocate memory");
error = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)class_gen);
check_jvmti_error(jvmti_env, error, "Cannot deallocate memory");
// manage references - see function top
(*jni_env)->PopLocalFrame(jni_env, NULL);
return net_ref;
}
static jint _get_class_id_for_class(JNIEnv * jni_env, jvmtiEnv * jvmti_env,
buffer * buff, jclass klass) {
jlong class_net_ref = get_tag(jvmti_env, klass);
if(class_net_ref == 0) {
class_net_ref =
_set_net_reference_for_class(jni_env, jvmti_env, buff, klass);
}
return net_ref_get_class_id(class_net_ref);
}
static jint _get_class_id_for_object(JNIEnv * jni_env, jvmtiEnv * jvmti_env,
buffer * buff, jobject obj) {
// get class of this object
jclass klass = _get_class_for_object(jni_env, obj);
// get class id of this class
jint class_id = _get_class_id_for_class(jni_env, jvmti_env, buff, klass);
// free local reference
(*jni_env)->DeleteLocalRef(jni_env, klass);
return class_id;
}
static jlong _set_net_reference_for_object(JNIEnv * jni_env,
jvmtiEnv * jvmti_env, buffer * buff, jobject obj) {