Change-Id: I07c0d3ec5c4ec51ea00fea539c930c6ed27b1163
Этот коммит содержится в:
Evgeny
2019-05-31 20:20:28 -05:00
родитель c0703c063c
Коммит 6d6eb2b2d0
10 изменённых файлов: 179 добавлений и 67 удалений
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
ROC Profiler library.
Profiling with metrics and traces based on perfcounters (PMC) and SQ threadtraces (SQTT).
Profiling with metrics and traces based on perfcounters (PMC) and traces (SQTT, PMC).
Implementation is based on AqlProfile HSA extension.
Library supports GFX8/GFX9.
+2
Просмотреть файл
@@ -56,6 +56,8 @@ set ( CMAKE_SHARED_LINKER_FLAGS "-Wl,-Bdynamic -Wl,-z,noexecstack" )
set ( CMAKE_SKIP_BUILD_RPATH TRUE )
add_definitions ( -DNEW_TRACE_API=1 )
## CLANG options
if ( "$ENV{CXX}" STREQUAL "/usr/bin/clang++" )
set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ferror-limit=1000000" )
+3 -4
Просмотреть файл
@@ -27,8 +27,7 @@ THE SOFTWARE.
// The goal of the implementation is to provide a HW specific low-level
// performance analysis interface for profiling of GPU compute applications.
// The profiling includes HW performance counters (PMC) with complex
// performance metrics and thread traces (SQTT). The profiling is supported
// by the SQTT, PMC and Callback APIs.
// performance metrics and traces: SQTT, SPM.
//
// The library can be used by a tool library loaded by HSA runtime or by
// higher level HW independent performance analysis API like PAPI.
@@ -66,8 +65,8 @@ uint32_t rocprofiler_version_minor();
typedef struct {
uint32_t intercept_mode;
uint32_t memcopy_tracking;
uint32_t sqtt_size;
uint32_t sqtt_local;
uint32_t trace_size;
uint32_t trace_local;
uint64_t timeout;
uint32_t timestamp_on;
} rocprofiler_settings_t;
+29 -17
Просмотреть файл
@@ -83,7 +83,7 @@ class Group {
Group(const util::AgentInfo* agent_info, Context* context, const uint32_t& index)
: pmc_profile_(agent_info),
sqtt_profile_(agent_info),
trace_profile_(agent_info),
n_profiles_(0),
refs_(1),
context_(context),
@@ -97,7 +97,7 @@ class Group {
pmc_profile_.Insert(info);
break;
case ROCPROFILER_FEATURE_KIND_TRACE:
sqtt_profile_.Insert(info);
trace_profile_.Insert(info);
break;
default:
EXC_RAISING(HSA_STATUS_ERROR, "bad rocprofiler feature kind (" << kind << ")");
@@ -107,21 +107,21 @@ class Group {
hsa_status_t Finalize() {
hsa_status_t status = pmc_profile_.Finalize(start_vector_, stop_vector_, read_vector_);
if (status == HSA_STATUS_SUCCESS) {
status = sqtt_profile_.Finalize(start_vector_, stop_vector_, read_vector_);
status = trace_profile_.Finalize(start_vector_, stop_vector_, read_vector_);
}
if (status == HSA_STATUS_SUCCESS) {
if (!pmc_profile_.Empty()) ++n_profiles_;
if (!sqtt_profile_.Empty()) ++n_profiles_;
if (!trace_profile_.Empty()) ++n_profiles_;
}
return status;
}
void GetProfiles(profile_vector_t& vec) {
pmc_profile_.GetProfiles(vec);
sqtt_profile_.GetProfiles(vec);
trace_profile_.GetProfiles(vec);
}
void GetTraceProfiles(profile_vector_t& vec) { sqtt_profile_.GetProfiles(vec); }
void GetTraceProfiles(profile_vector_t& vec) { trace_profile_.GetProfiles(vec); }
info_vector_t& GetInfoVector() { return info_vector_; }
const pkt_vector_t& GetStartVector() const { return start_vector_; }
@@ -137,7 +137,7 @@ class Group {
private:
PmcProfile pmc_profile_;
SqttProfile sqtt_profile_;
TraceProfile trace_profile_;
info_vector_t info_vector_;
pkt_vector_t start_vector_;
pkt_vector_t stop_vector_;
@@ -361,9 +361,9 @@ class Context {
rocprofiler_feature_t* info = &info_array[i];
const rocprofiler_feature_kind_t kind = info->kind;
const char* name = info->name;
if (!name) EXC_RAISING(HSA_STATUS_ERROR, "input feature name is NULL");
info_map_[name] = info;
if (kind == ROCPROFILER_FEATURE_KIND_METRIC) {
if (name == NULL) EXC_RAISING(HSA_STATUS_ERROR, "metric name is NULL");
info_map_[name] = info;
auto ret = metrics_map_.insert({name, NULL});
if (!ret.second)
EXC_RAISING(HSA_STATUS_ERROR, "input metric '" << name
@@ -435,7 +435,19 @@ class Context {
set_[group_index].Insert(profile_info_t{event, NULL, 0, info});
}
} else if (kind == ROCPROFILER_FEATURE_KIND_TRACE) { // Processing traces features
set_[0].Insert(profile_info_t{NULL, info->parameters, info->parameter_count, info});
if (name != NULL) {
const Metric* metric = metrics_->Get(name);
if (metric == NULL)
EXC_RAISING(HSA_STATUS_ERROR, "input metric '" << name << "' is not found");
counters_vec_t counters_vec = metric->GetCounters();
if (counters_vec.size() != 1)
EXC_RAISING(HSA_STATUS_ERROR, "trace bad metric '" << name << "' is not base counter");
const counter_t* counter = counters_vec[0];
const event_t* event = &(counter->event);
set_[0].Insert(profile_info_t{event, NULL, 0, info});
} else {
set_[0].Insert(profile_info_t{NULL, info->parameters, info->parameter_count, info});
}
} else {
EXC_RAISING(HSA_STATUS_ERROR, "bad rocprofiler feature kind (" << kind << ")");
}
@@ -484,15 +496,15 @@ class Context {
if (ainfo_data->sample_id == 0) rinfo->data.result_int64 = 0;
rinfo->data.result_int64 += ainfo_data->pmc_data.result;
rinfo->data.kind = ROCPROFILER_DATA_KIND_INT64;
} else if (ainfo_type == HSA_VEN_AMD_AQLPROFILE_INFO_SQTT_DATA) {
} else if (ainfo_type == HSA_VEN_AMD_AQLPROFILE_INFO_TRACE_DATA) {
if (rinfo->data.result_bytes.copy) {
const bool sqtt_local = SqttProfile::IsLocal();
const bool trace_local = TraceProfile::IsLocal();
util::HsaRsrcFactory* hsa_rsrc = &util::HsaRsrcFactory::Instance();
if (sample_id == 0) {
const uint32_t output_buffer_size = profile->output_buffer.size;
const uint32_t output_buffer_size64 = profile->output_buffer.size / sizeof(uint64_t);
const util::AgentInfo* agent_info = hsa_rsrc->GetAgentInfo(profile->agent);
void* ptr = (sqtt_local) ? hsa_rsrc->AllocateSysMemory(agent_info, output_buffer_size) :
void* ptr = (trace_local) ? hsa_rsrc->AllocateSysMemory(agent_info, output_buffer_size) :
calloc(output_buffer_size64, sizeof(uint64_t));
rinfo->data.result_bytes.size = output_buffer_size;
rinfo->data.result_bytes.ptr = ptr;
@@ -500,19 +512,19 @@ class Context {
}
char* result_bytes_ptr = reinterpret_cast<char*>(rinfo->data.result_bytes.ptr);
const char* end = result_bytes_ptr + rinfo->data.result_bytes.size;
const char* src = reinterpret_cast<char*>(ainfo_data->sqtt_data.ptr);
uint32_t size = ainfo_data->sqtt_data.size;
const char* src = reinterpret_cast<char*>(ainfo_data->trace_data.ptr);
uint32_t size = ainfo_data->trace_data.size;
char* ptr = callback_data->ptr;
uint32_t* header = reinterpret_cast<uint32_t*>(ptr);
char* dest = ptr + sizeof(*header);
if ((dest + size) >= end) {
if (dest < end) size = end - dest;
else EXC_RAISING(HSA_STATUS_ERROR, "SQTT data out of output buffer");
else EXC_RAISING(HSA_STATUS_ERROR, "Trace data out of output buffer");
}
bool suc = true;
if (sqtt_local) {
if (trace_local) {
suc = hsa_rsrc->Memcpy(profile->agent, dest, src, size);
} else {
memcpy(dest, src, size);
+6 -3
Просмотреть файл
@@ -236,19 +236,22 @@ class PmcProfile : public Profile {
}
};
class SqttProfile : public Profile {
class TraceProfile : public Profile {
public:
static inline void SetSize(const uint32_t& size) { output_buffer_size_ = size; }
static inline uint32_t GetSize() { return output_buffer_size_; }
static inline void SetLocal(const bool& b) { output_buffer_local_ = b; }
static inline bool IsLocal() { return output_buffer_local_; }
SqttProfile(const util::AgentInfo* agent_info) : Profile(agent_info) {
profile_.type = HSA_VEN_AMD_AQLPROFILE_EVENT_TYPE_SQTT;
TraceProfile(const util::AgentInfo* agent_info) : Profile(agent_info) {
profile_.type = HSA_VEN_AMD_AQLPROFILE_EVENT_TYPE_TRACE;
}
void Insert(const profile_info_t& info) {
Profile::Insert(info);
if (info.event != NULL) {
Config<event_t>(&profile_).Insert(*(info.event));
}
for (unsigned j = 0; j < info.parameter_count; ++j) {
Config<parameter_t>(&profile_).Insert(info.parameters[j]);
}
+6 -6
Просмотреть файл
@@ -175,16 +175,16 @@ uint32_t LoadTool() {
rocprofiler_settings_t settings{};
settings.intercept_mode = (intercept_mode != 0) ? 1 : 0;
settings.sqtt_size = SqttProfile::GetSize();
settings.sqtt_local = SqttProfile::IsLocal() ? 1: 0;
settings.trace_size = TraceProfile::GetSize();
settings.trace_local = TraceProfile::IsLocal() ? 1: 0;
settings.timeout = util::HsaRsrcFactory::GetTimeoutNs();
settings.timestamp_on = InterceptQueue::IsTrackerOn() ? 1 : 0;
if (handler) handler();
else if (handler_prop) handler_prop(&settings);
SqttProfile::SetSize(settings.sqtt_size);
SqttProfile::SetLocal(settings.sqtt_local != 0);
TraceProfile::SetSize(settings.trace_size);
TraceProfile::SetLocal(settings.trace_local != 0);
util::HsaRsrcFactory::SetTimeoutNs(settings.timeout);
InterceptQueue::TrackerOn(settings.timestamp_on != 0);
if (settings.intercept_mode != 0) intercept_mode = DISPATCH_INTERCEPT_MODE;
@@ -384,8 +384,8 @@ hsa_status_t hsa_amd_memory_async_copy_rect_interceptor(
}
rocprofiler_properties_t rocprofiler_properties;
uint32_t SqttProfile::output_buffer_size_ = 0x2000000; // 32M
bool SqttProfile::output_buffer_local_ = true;
uint32_t TraceProfile::output_buffer_size_ = 0x2000000; // 32M
bool TraceProfile::output_buffer_local_ = true;
std::atomic<Tracker*> Tracker::instance_{};
Tracker::mutex_t Tracker::glob_mutex_;
Tracker::counter_t Tracker::counter_ = 0;
+12
Просмотреть файл
@@ -23,6 +23,8 @@ THE SOFTWARE.
#ifndef SRC_CORE_TYPES_H_
#define SRC_CORE_TYPES_H_
#include <iostream>
#include <hsa_ven_amd_aqlprofile.h>
namespace rocprofiler {
@@ -33,6 +35,16 @@ typedef hsa_ven_amd_aqlprofile_profile_t profile_t;
typedef hsa_ext_amd_aql_pm4_packet_t packet_t;
typedef uint32_t packet_word_t;
typedef uint64_t timestamp_t;
inline std::ostream& operator<< (std::ostream& out, const event_t& event) {
out << "[block_name(" << event.block_name << "). block_index(" << event.block_index << "). counter_id(" << event.counter_id << ")]";
return out;
}
inline std::ostream& operator<< (std::ostream& out, const parameter_t& parameter) {
out << "[parameter_name(" << parameter.parameter_name << "). value(" << parameter.value << ")]";
return out;
}
} // namespace rocprofiler
#endif // SRC_CORE_TYPES_H_
+27 -8
Просмотреть файл
@@ -22,21 +22,31 @@
# THE SOFTWARE.
################################################################################
test_filter=-1
if [ -n "$1" ] ; then
test_filter=$1
fi
# test check routin
test_status=0
test_number=0
xeval_test() {
test_number=$test_number
}
eval_test() {
label=$1
cmdline=$2
echo "$label: \"$cmdline\""
eval "$cmdline"
if [ $? != 0 ] ; then
echo "$label: FAILED"
test_status=$(($test_status + 1))
else
echo "$label: PASSED"
if [ $test_filter = -1 -o $test_filter = $test_number ] ; then
echo "$label: \"$cmdline\""
eval "$cmdline"
if [ $? != 0 ] ; then
echo "$label: FAILED"
test_status=$(($test_status + 1))
else
echo "$label: PASSED"
fi
fi
test_number=$(($test_number + 1))
test_number=$((test_number + 1))
}
# enable tools load failure reporting
@@ -97,6 +107,15 @@ export ROCP_THRS=10
export ROCP_INPUT=input1.xml
eval_test "'rocprof' libtool test n-threads" ./test/ctrl
## SPM test
export ROCP_KITER=1
export ROCP_DITER=1
export ROCP_AGENTS=1
export ROCP_THRS=1
export ROCP_INPUT=spm_input.xml
xeval_test "libtool test, SPM trace test" ./test/ctrl
## Libtool test, counter sets
# Memcopies tracking
+11
Просмотреть файл
@@ -0,0 +1,11 @@
# List of metrics
<metric
name=SQ_WAVES,SQ_INSTS_SMEM,SQ_INSTS_VALU
></metric>
# SPM trace with parameters
<trace name="SPM">
<parameters
SAMPLE_RATE=256
></parameters>
</trace>
+82 -28
Просмотреть файл
@@ -134,8 +134,10 @@ static uint32_t CTX_OUTSTANDING_MAX = 0;
static uint32_t CTX_OUTSTANDING_MON = 0;
// to truncate kernel names
uint32_t to_truncate_names = 0;
// local SQTT buffer
bool is_sqtt_local = true;
// local trace buffer
bool is_trace_local = true;
// SPM trace enabled
bool is_spm_trace = false;
static inline uint32_t GetPid() { return syscall(__NR_getpid); }
static inline uint32_t GetTid() { return syscall(__NR_gettid); }
@@ -281,7 +283,7 @@ void dealloc_context_entry(context_entry_t* entry) {
// Dump trace data to file
void dump_sqtt_trace(const char* label, const uint32_t chunk, const void* data, const uint32_t& size) {
if (result_prefix != NULL) {
// Open SQTT file
// Open file
std::ostringstream oss;
oss << result_prefix << "/thread_trace_" << label << "_se" << chunk << ".out";
FILE* file = fopen(oss.str().c_str(), "w");
@@ -298,11 +300,36 @@ void dump_sqtt_trace(const char* label, const uint32_t chunk, const void* data,
fprintf(file, "%04x\n", ptr[i]);
}
// Close SQTT file
// Close file
fclose(file);
}
}
// Dump trace data to file
void dump_spm_trace(const char* label, const void* data, const uint32_t& size) {
if (result_prefix != NULL) {
// Open trace file
std::ostringstream oss;
oss << result_prefix << "/spm_trace_" << label << ".out";
const int fd = open(oss.str().c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0666);
if (fd == -1) {
std::ostringstream errmsg;
errmsg << "open error, file '" << oss.str().c_str() << "'";
perror(errmsg.str().c_str());
abort();
}
// write trace binary data
if (write(fd, data, size) == -1) {
std::ostringstream errmsg;
errmsg << "write error, file '" << oss.str().c_str() << "'";
perror(errmsg.str().c_str());
abort();
}
// Close file
close(fd);
}
}
struct trace_data_arg_t {
FILE* file;
const char* label;
@@ -314,23 +341,43 @@ hsa_status_t trace_data_cb(hsa_ven_amd_aqlprofile_info_type_t info_type,
hsa_ven_amd_aqlprofile_info_data_t* info_data, void* data) {
hsa_status_t status = HSA_STATUS_SUCCESS;
trace_data_arg_t* arg = reinterpret_cast<trace_data_arg_t*>(data);
if (info_type == HSA_VEN_AMD_AQLPROFILE_INFO_SQTT_DATA) {
const void* data_ptr = info_data->sqtt_data.ptr;
const uint32_t data_size = info_data->sqtt_data.size;
fprintf(arg->file, " SE(%u) size(%u)\n", info_data->sample_id, data_size);
if (info_type == HSA_VEN_AMD_AQLPROFILE_INFO_TRACE_DATA) {
if (is_spm_trace) {
if (info_data->sample_id != 0) {
fatal("Only one SPM sample expected");
}
const void* data_ptr = info_data->trace_data.ptr;
const uint32_t data_size = info_data->trace_data.size;
fprintf(arg->file, " size(%u)\n", data_size);
if (is_sqtt_local) {
if (is_trace_local == false) fatal("SPM trace supports only local trace allocation");
HsaRsrcFactory* hsa_rsrc = &HsaRsrcFactory::Instance();
const AgentInfo* agent_info = hsa_rsrc->GetAgentInfo(arg->agent);
const uint32_t mem_size = data_size;
void* buffer = hsa_rsrc->AllocateSysMemory(agent_info, mem_size);
if(!hsa_rsrc->Memcpy(agent_info, buffer, data_ptr, mem_size)) {
fatal("SQTT data memcopy to host failed");
fatal("Trace data memcopy to host failed");
}
dump_sqtt_trace(arg->label, info_data->sample_id, buffer, data_size);
dump_spm_trace(arg->label, buffer, data_size);
HsaRsrcFactory::FreeMemory(buffer);
} else {
dump_sqtt_trace(arg->label, info_data->sample_id, data_ptr, data_size);
const void* data_ptr = info_data->trace_data.ptr;
const uint32_t data_size = info_data->trace_data.size;
fprintf(arg->file, " SE(%u) size(%u)\n", info_data->sample_id, data_size);
if (is_trace_local) {
HsaRsrcFactory* hsa_rsrc = &HsaRsrcFactory::Instance();
const AgentInfo* agent_info = hsa_rsrc->GetAgentInfo(arg->agent);
const uint32_t mem_size = data_size;
void* buffer = hsa_rsrc->AllocateSysMemory(agent_info, mem_size);
if(!hsa_rsrc->Memcpy(agent_info, buffer, data_ptr, mem_size)) {
fatal("Trace data memcopy to host failed");
}
dump_sqtt_trace(arg->label, info_data->sample_id, buffer, data_size);
HsaRsrcFactory::FreeMemory(buffer);
} else {
dump_sqtt_trace(arg->label, info_data->sample_id, data_ptr, data_size);
}
}
} else
status = HSA_STATUS_ERROR;
@@ -367,12 +414,12 @@ void output_results(const context_entry_t* entry, const char* label) {
for (unsigned i = 0; i < p->data.result_bytes.instance_count; ++i) {
const uint32_t chunk_size = *reinterpret_cast<const uint32_t*>(ptr);
const char* chunk_data = ptr + sizeof(uint32_t);
if (chunk_data >= end) fatal("SQTT data is out of the result buffer size");
if (chunk_data >= end) fatal("Trace data is out of the result buffer size");
dump_sqtt_trace(label, i, chunk_data, chunk_size);
const uint32_t off = align_size(chunk_size, sizeof(uint32_t));
ptr = chunk_data + off;
if (chunk_data >= end) fatal("SQTT data ptr is out of the result buffer size");
if (chunk_data >= end) fatal("Trace data ptr is out of the result buffer size");
size += chunk_size;
}
fprintf(file, "size(%lu)\n", size);
@@ -821,19 +868,19 @@ extern "C" PUBLIC_API void OnLoadToolProp(rocprofiler_settings_t* settings)
if (it != opts.end()) { CTX_OUTSTANDING_MAX = atol(it->second.c_str()); }
it = opts.find("heartbeat");
if (it != opts.end()) { CTX_OUTSTANDING_MON = atol(it->second.c_str()); }
it = opts.find("sqtt-size");
it = opts.find("trace-size");
if (it != opts.end()) {
std::string str = normalize_token(it->second, true, "option sqtt-size");
std::string str = normalize_token(it->second, true, "option trace-size");
uint32_t multiplier = 1;
switch (str.back()) {
case 'K': multiplier = 1024; break;
case 'M': multiplier = 1024 * 1024; break;
}
if (multiplier != 1) str = str.substr(0, str.length() - 1);
settings->sqtt_size = strtoull(str.c_str(), NULL, 0) * multiplier;
settings->trace_size = strtoull(str.c_str(), NULL, 0) * multiplier;
}
it = opts.find("sqtt-local");
if (it != opts.end()) { settings->sqtt_local = (it->second == "on"); }
it = opts.find("trace-local");
if (it != opts.end()) { settings->trace_local = (it->second == "on"); }
it = opts.find("memcopies");
if (it != opts.end()) { settings->memcopy_tracking = (it->second == "on"); }
}
@@ -850,14 +897,14 @@ extern "C" PUBLIC_API void OnLoadToolProp(rocprofiler_settings_t* settings)
check_env_var("ROCP_TIMESTAMP_ON", settings->timestamp_on);
// Set data timeout
check_env_var("ROCP_DATA_TIMEOUT", settings->timeout);
// Set SQTT size
check_env_var("ROCP_SQTT_SIZE", settings->sqtt_size);
// Set SQTT local buffer
check_env_var("ROCP_SQTT_LOCAL", settings->sqtt_local);
// Set trace size
check_env_var("ROCP_TRACE_SIZE", settings->trace_size);
// Set trace local buffer
check_env_var("ROCP_TRACE_LOCAL", settings->trace_local);
// Set memcopies tracking
check_env_var("ROCP_MCOPY_TRACKING", settings->memcopy_tracking);
is_sqtt_local = settings->sqtt_local;
is_trace_local = settings->trace_local;
// Printing out info
char* info_symb = getenv("ROCP_INFO");
@@ -943,6 +990,7 @@ extern "C" PUBLIC_API void OnLoadToolProp(rocprofiler_settings_t* settings)
// Getting traces
const auto traces_list = xml->GetNodes("top.trace");
if (traces_list.size() > 1) fatal("ROCProfiler: only one trace supported at a time");
const unsigned feature_count = metrics_vec.size() + traces_list.size();
rocprofiler_feature_t* features = new rocprofiler_feature_t[feature_count];
@@ -966,7 +1014,8 @@ extern "C" PUBLIC_API void OnLoadToolProp(rocprofiler_settings_t* settings)
auto it = entry->opts.find("name");
if (it == entry->opts.end()) fatal("ROCProfiler: trace name is missing");
const std::string& name = it->second;
if (name != "SQTT") continue;
if (name == "SPM") is_spm_trace = true;
traces_found++;
bool to_copy_data = false;
@@ -988,15 +1037,14 @@ extern "C" PUBLIC_API void OnLoadToolProp(rocprofiler_settings_t* settings)
HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_TOKEN_MASK;
parameters_dict["TOKEN_MASK2"] =
HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_TOKEN_MASK2;
#ifdef AQLPROF_NEW_API
parameters_dict["SE_MASK"] =
HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_SE_MASK;
#endif
parameters_dict["SAMPLE_RATE"] =
HSA_VEN_AMD_AQLPROFILE_PARAMETER_NAME_SAMPLE_RATE;
printf(" %s (", name.c_str());
features[index] = {};
features[index].kind = ROCPROFILER_FEATURE_KIND_TRACE;
features[index].name = strdup(name.c_str());
features[index].data.result_bytes.copy = to_copy_data;
uint32_t parameter_count = 0;
@@ -1036,6 +1084,12 @@ extern "C" PUBLIC_API void OnLoadToolProp(rocprofiler_settings_t* settings)
fflush(stdout);
const uint32_t features_found = metrics_vec.size() + traces_found;
if (is_spm_trace) {
for (uint32_t index = 0; index < features_found; index++) {
features[index].kind = ROCPROFILER_FEATURE_KIND_TRACE;
}
}
// Context array aloocation
context_array = new context_array_t;