| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| % Latex header for doxygen 1.8.3.1 | ||
| \documentclass{book} | ||
| \usepackage[a4paper,top=2.5cm,bottom=2.5cm,left=2.5cm,right=2.5cm]{geometry} | ||
| \usepackage{makeidx} | ||
| \usepackage{natbib} | ||
| \usepackage{graphicx} | ||
| \usepackage{multicol} | ||
| \usepackage{float} | ||
| \usepackage{listings} | ||
| \usepackage{color} | ||
| \usepackage{ifthen} | ||
| \usepackage[table]{xcolor} | ||
| \usepackage{textcomp} | ||
| \usepackage{alltt} | ||
| \usepackage{ifpdf} | ||
| \ifpdf | ||
| \usepackage[pdftex, | ||
| pagebackref=true, | ||
| colorlinks=true, | ||
| linkcolor=blue, | ||
| unicode | ||
| ]{hyperref} | ||
| \else | ||
| \usepackage[ps2pdf, | ||
| pagebackref=true, | ||
| colorlinks=true, | ||
| linkcolor=blue, | ||
| unicode | ||
| ]{hyperref} | ||
| \usepackage{pspicture} | ||
| \fi | ||
| \usepackage[utf8]{inputenc} | ||
| \usepackage{mathptmx} | ||
| \usepackage[scaled=.90]{helvet} | ||
| \usepackage{courier} | ||
| \usepackage{sectsty} | ||
| \usepackage{amssymb} | ||
| \usepackage[titles]{tocloft} | ||
| \usepackage{doxygen} | ||
| \usepackage{fancyhdr} | ||
| \pagestyle{fancy} | ||
| \lstset{language=C++,inputencoding=utf8,basicstyle=\footnotesize,breaklines=true,breakatwhitespace=true,tabsize=4,numbers=left } | ||
| \makeindex | ||
| \setcounter{tocdepth}{3} | ||
| \renewcommand{\footrulewidth}{0.4pt} | ||
| \renewcommand{\familydefault}{\sfdefault} | ||
| \hfuzz=15pt | ||
| \setlength{\emergencystretch}{15pt} | ||
| \hbadness=750 | ||
| \tolerance=750 | ||
| \begin{document} | ||
| \hypersetup{pageanchor=false,citecolor=blue} | ||
| \begin{titlepage} | ||
| \vspace*{7cm} | ||
| \begin{center} | ||
| {\Large Intel\textsuperscript{\textregistered} Offload Runtime Library }\\ | ||
| \vspace*{1cm} | ||
| {\large Generated by Doxygen $doxygenversion }\\ | ||
| \vspace*{0.5cm} | ||
| {\small $datetime }\\ | ||
| \end{center} | ||
| \end{titlepage} | ||
| {\bf FTC Optimization Notice} | ||
| Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for | ||
| optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, | ||
| SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the | ||
| availability, functionality, or effectiveness of any optimization on microprocessors not | ||
| manufactured by Intel. | ||
| Microprocessor-dependent optimizations in this product are intended for use with Intel | ||
| microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for | ||
| Intel microprocessors. Please refer to the applicable product User and Reference Guides for | ||
| more information regarding the specific instruction sets covered by this notice. | ||
| Notice revision \#20110804 | ||
| \vspace*{0.5cm} | ||
| {\bf Trademarks} | ||
| Intel, Xeon, and Intel Xeon Phi are trademarks of Intel Corporation in the U.S. and/or other countries. | ||
| This document is Copyright \textcopyright 2014, Intel Corporation. All rights reserved. | ||
| \pagenumbering{roman} | ||
| \tableofcontents | ||
| \pagenumbering{arabic} | ||
| \hypersetup{pageanchor=true,citecolor=blue} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,344 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #include "cean_util.h" | ||
| #include "offload_common.h" | ||
|
|
||
| // 1. allocate element of CeanReadRanges type | ||
| // 2. initialized it for reading consequently contiguous ranges | ||
| // described by "ap" argument | ||
| CeanReadRanges * init_read_ranges_arr_desc(const arr_desc *ap) | ||
| { | ||
| CeanReadRanges * res; | ||
|
|
||
| // find the max contiguous range | ||
| int64_t rank = ap->rank - 1; | ||
| int64_t length = ap->dim[rank].size; | ||
| for (; rank >= 0; rank--) { | ||
| if (ap->dim[rank].stride == 1) { | ||
| length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1); | ||
| if (rank > 0 && length != ap->dim[rank - 1].size) { | ||
| break; | ||
| } | ||
| } | ||
| else { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| res =(CeanReadRanges *)malloc(sizeof(CeanReadRanges) + | ||
| (ap->rank - rank) * sizeof(CeanReadDim)); | ||
| res->current_number = 0; | ||
| res->range_size = length; | ||
| res->last_noncont_ind = rank; | ||
|
|
||
| // calculate number of contiguous ranges inside noncontiguous dimensions | ||
| int count = 1; | ||
| bool prev_is_cont = true; | ||
| int64_t offset = 0; | ||
|
|
||
| for (; rank >= 0; rank--) { | ||
| res->Dim[rank].count = count; | ||
| res->Dim[rank].size = ap->dim[rank].stride * ap->dim[rank].size; | ||
| count *= (prev_is_cont && ap->dim[rank].stride == 1? 1 : | ||
| (ap->dim[rank].upper - ap->dim[rank].lower + | ||
| ap->dim[rank].stride) / ap->dim[rank].stride); | ||
| prev_is_cont = false; | ||
| offset +=(ap->dim[rank].lower - ap->dim[rank].lindex) * | ||
| ap->dim[rank].size; | ||
| } | ||
| res->range_max_number = count; | ||
| res -> ptr = (void*)ap->base; | ||
| res -> init_offset = offset; | ||
| return res; | ||
| } | ||
|
|
||
| // check if ranges described by 1 argument could be transfered into ranges | ||
| // described by 2-nd one | ||
| bool cean_ranges_match( | ||
| CeanReadRanges * read_rng1, | ||
| CeanReadRanges * read_rng2 | ||
| ) | ||
| { | ||
| return ( read_rng1 == NULL || read_rng2 == NULL || | ||
| (read_rng1->range_size % read_rng2->range_size == 0 || | ||
| read_rng2->range_size % read_rng1->range_size == 0)); | ||
| } | ||
|
|
||
| // Set next offset and length and returns true for next range. | ||
| // Returns false if the ranges are over. | ||
| bool get_next_range( | ||
| CeanReadRanges * read_rng, | ||
| int64_t *offset | ||
| ) | ||
| { | ||
| if (++read_rng->current_number > read_rng->range_max_number) { | ||
| read_rng->current_number = 0; | ||
| return false; | ||
| } | ||
| int rank = 0; | ||
| int num = read_rng->current_number - 1; | ||
| int64_t cur_offset = 0; | ||
| int num_loc; | ||
| for (; rank <= read_rng->last_noncont_ind; rank++) { | ||
| num_loc = num / read_rng->Dim[rank].count; | ||
| cur_offset += num_loc * read_rng->Dim[rank].size; | ||
| num = num % read_rng->Dim[rank].count; | ||
| } | ||
| *offset = cur_offset + read_rng->init_offset; | ||
| return true; | ||
| } | ||
|
|
||
| bool is_arr_desc_contiguous(const arr_desc *ap) | ||
| { | ||
| int64_t rank = ap->rank - 1; | ||
| int64_t length = ap->dim[rank].size; | ||
| for (; rank >= 0; rank--) { | ||
| if (ap->dim[rank].stride > 1 && | ||
| ap->dim[rank].upper - ap->dim[rank].lower != 0) { | ||
| return false; | ||
| } | ||
| else if (length != ap->dim[rank].size) { | ||
| for (; rank >= 0; rank--) { | ||
| if (ap->dim[rank].upper - ap->dim[rank].lower != 0) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1); | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| int64_t cean_get_transf_size(CeanReadRanges * read_rng) | ||
| { | ||
| return(read_rng->range_max_number * read_rng->range_size); | ||
| } | ||
|
|
||
| static uint64_t last_left, last_right; | ||
| typedef void (*fpp)(const char *spaces, uint64_t low, uint64_t high, int esize); | ||
|
|
||
| static void generate_one_range( | ||
| const char *spaces, | ||
| uint64_t lrange, | ||
| uint64_t rrange, | ||
| fpp fp, | ||
| int esize | ||
| ) | ||
| { | ||
| OFFLOAD_TRACE(3, | ||
| "%s generate_one_range(lrange=%p, rrange=%p, esize=%d)\n", | ||
| spaces, (void*)lrange, (void*)rrange, esize); | ||
| if (last_left == -1) { | ||
| // First range | ||
| last_left = lrange; | ||
| } | ||
| else { | ||
| if (lrange == last_right+1) { | ||
| // Extend previous range, don't print | ||
| } | ||
| else { | ||
| (*fp)(spaces, last_left, last_right, esize); | ||
| last_left = lrange; | ||
| } | ||
| } | ||
| last_right = rrange; | ||
| } | ||
|
|
||
| static void generate_mem_ranges_one_rank( | ||
| const char *spaces, | ||
| uint64_t base, | ||
| uint64_t rank, | ||
| const struct dim_desc *ddp, | ||
| fpp fp, | ||
| int esize | ||
| ) | ||
| { | ||
| uint64_t lindex = ddp->lindex; | ||
| uint64_t lower = ddp->lower; | ||
| uint64_t upper = ddp->upper; | ||
| uint64_t stride = ddp->stride; | ||
| uint64_t size = ddp->size; | ||
| OFFLOAD_TRACE(3, | ||
| "%s " | ||
| "generate_mem_ranges_one_rank(base=%p, rank=%lld, lindex=%lld, " | ||
| "lower=%lld, upper=%lld, stride=%lld, size=%lld, esize=%d)\n", | ||
| spaces, (void*)base, rank, lindex, lower, upper, stride, size, esize); | ||
| if (rank == 1) { | ||
| uint64_t lrange, rrange; | ||
| if (stride == 1) { | ||
| lrange = base + (lower-lindex)*size; | ||
| rrange = lrange + (upper-lower+1)*size - 1; | ||
| generate_one_range(spaces, lrange, rrange, fp, esize); | ||
| } | ||
| else { | ||
| for (int i=lower-lindex; i<=upper-lindex; i+=stride) { | ||
| lrange = base + i*size; | ||
| rrange = lrange + size - 1; | ||
| generate_one_range(spaces, lrange, rrange, fp, esize); | ||
| } | ||
| } | ||
| } | ||
| else { | ||
| for (int i=lower-lindex; i<=upper-lindex; i+=stride) { | ||
| generate_mem_ranges_one_rank( | ||
| spaces, base+i*size, rank-1, ddp+1, fp, esize); | ||
|
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| static void generate_mem_ranges( | ||
| const char *spaces, | ||
| const arr_desc *adp, | ||
| bool deref, | ||
| fpp fp | ||
| ) | ||
| { | ||
| uint64_t esize; | ||
|
|
||
| OFFLOAD_TRACE(3, | ||
| "%s " | ||
| "generate_mem_ranges(adp=%p, deref=%d, fp)\n", | ||
| spaces, adp, deref); | ||
| last_left = -1; | ||
| last_right = -2; | ||
|
|
||
| // Element size is derived from last dimension | ||
| esize = adp->dim[adp->rank-1].size; | ||
|
|
||
| generate_mem_ranges_one_rank( | ||
| // For c_cean_var the base addr is the address of the data | ||
| // For c_cean_var_ptr the base addr is dereferenced to get to the data | ||
| spaces, deref ? *((uint64_t*)(adp->base)) : adp->base, | ||
| adp->rank, &adp->dim[0], fp, esize); | ||
| (*fp)(spaces, last_left, last_right, esize); | ||
| } | ||
|
|
||
| // returns offset and length of the data to be transferred | ||
| void __arr_data_offset_and_length( | ||
| const arr_desc *adp, | ||
| int64_t &offset, | ||
| int64_t &length | ||
| ) | ||
| { | ||
| int64_t rank = adp->rank - 1; | ||
| int64_t size = adp->dim[rank].size; | ||
| int64_t r_off = 0; // offset from right boundary | ||
|
|
||
| // find the rightmost dimension which takes just part of its | ||
| // range. We define it if the size of left rank is not equal | ||
| // the range's length between upper and lower boungaries | ||
| while (rank > 0) { | ||
| size *= (adp->dim[rank].upper - adp->dim[rank].lower + 1); | ||
| if (size != adp->dim[rank - 1].size) { | ||
| break; | ||
| } | ||
| rank--; | ||
| } | ||
|
|
||
| offset = (adp->dim[rank].lower - adp->dim[rank].lindex) * | ||
| adp->dim[rank].size; | ||
|
|
||
| // find gaps both from the left - offset and from the right - r_off | ||
| for (rank--; rank >= 0; rank--) { | ||
| offset += (adp->dim[rank].lower - adp->dim[rank].lindex) * | ||
| adp->dim[rank].size; | ||
| r_off += adp->dim[rank].size - | ||
| (adp->dim[rank + 1].upper - adp->dim[rank + 1].lindex + 1) * | ||
| adp->dim[rank + 1].size; | ||
| } | ||
| length = (adp->dim[0].upper - adp->dim[0].lindex + 1) * | ||
| adp->dim[0].size - offset - r_off; | ||
| } | ||
|
|
||
| #if OFFLOAD_DEBUG > 0 | ||
|
|
||
| void print_range( | ||
| const char *spaces, | ||
| uint64_t low, | ||
| uint64_t high, | ||
| int esize | ||
| ) | ||
| { | ||
| char buffer[1024]; | ||
| char number[32]; | ||
|
|
||
| OFFLOAD_TRACE(3, "%s print_range(low=%p, high=%p, esize=%d)\n", | ||
| spaces, (void*)low, (void*)high, esize); | ||
|
|
||
| if (console_enabled < 4) { | ||
| return; | ||
| } | ||
| OFFLOAD_TRACE(4, "%s values:\n", spaces); | ||
| int count = 0; | ||
| buffer[0] = '\0'; | ||
| while (low <= high) | ||
| { | ||
| switch (esize) | ||
| { | ||
| case 1: | ||
| sprintf(number, "%d ", *((char *)low)); | ||
| low += 1; | ||
| break; | ||
| case 2: | ||
| sprintf(number, "%d ", *((short *)low)); | ||
| low += 2; | ||
| break; | ||
| case 4: | ||
| sprintf(number, "%d ", *((int *)low)); | ||
| low += 4; | ||
| break; | ||
| default: | ||
| sprintf(number, "0x%016x ", *((uint64_t *)low)); | ||
| low += 8; | ||
| break; | ||
| } | ||
| strcat(buffer, number); | ||
| count++; | ||
| if (count == 10) { | ||
| OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer); | ||
| count = 0; | ||
| buffer[0] = '\0'; | ||
| } | ||
| } | ||
| if (count != 0) { | ||
| OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer); | ||
| } | ||
| } | ||
|
|
||
| void __arr_desc_dump( | ||
| const char *spaces, | ||
| const char *name, | ||
| const arr_desc *adp, | ||
| bool deref | ||
| ) | ||
| { | ||
| OFFLOAD_TRACE(2, "%s%s CEAN expression %p\n", spaces, name, adp); | ||
|
|
||
| if (adp != 0) { | ||
| OFFLOAD_TRACE(2, "%s base=%llx, rank=%lld\n", | ||
| spaces, adp->base, adp->rank); | ||
|
|
||
| for (int i = 0; i < adp->rank; i++) { | ||
| OFFLOAD_TRACE(2, | ||
| "%s dimension %d: size=%lld, lindex=%lld, " | ||
| "lower=%lld, upper=%lld, stride=%lld\n", | ||
| spaces, i, adp->dim[i].size, adp->dim[i].lindex, | ||
| adp->dim[i].lower, adp->dim[i].upper, | ||
| adp->dim[i].stride); | ||
| } | ||
| // For c_cean_var the base addr is the address of the data | ||
| // For c_cean_var_ptr the base addr is dereferenced to get to the data | ||
| generate_mem_ranges(spaces, adp, deref, &print_range); | ||
| } | ||
| } | ||
| #endif // OFFLOAD_DEBUG |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #ifndef CEAN_UTIL_H_INCLUDED | ||
| #define CEAN_UTIL_H_INCLUDED | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| // CEAN expression representation | ||
| struct dim_desc { | ||
| int64_t size; // Length of data type | ||
| int64_t lindex; // Lower index | ||
| int64_t lower; // Lower section bound | ||
| int64_t upper; // Upper section bound | ||
| int64_t stride; // Stride | ||
| }; | ||
|
|
||
| struct arr_desc { | ||
| int64_t base; // Base address | ||
| int64_t rank; // Rank of array | ||
| dim_desc dim[1]; | ||
| }; | ||
|
|
||
| struct CeanReadDim { | ||
| int64_t count; // The number of elements in this dimension | ||
| int64_t size; // The number of bytes between successive | ||
| // elements in this dimension. | ||
| }; | ||
|
|
||
| struct CeanReadRanges { | ||
| void * ptr; | ||
| int64_t current_number; // the number of ranges read | ||
| int64_t range_max_number; // number of contiguous ranges | ||
| int64_t range_size; // size of max contiguous range | ||
| int last_noncont_ind; // size of Dim array | ||
| int64_t init_offset; // offset of 1-st element from array left bound | ||
| CeanReadDim Dim[1]; | ||
| }; | ||
|
|
||
| // array descriptor length | ||
| #define __arr_desc_length(rank) \ | ||
| (sizeof(int64_t) + sizeof(dim_desc) * (rank)) | ||
|
|
||
| // returns offset and length of the data to be transferred | ||
| void __arr_data_offset_and_length(const arr_desc *adp, | ||
| int64_t &offset, | ||
| int64_t &length); | ||
|
|
||
| // define if data array described by argument is contiguous one | ||
| bool is_arr_desc_contiguous(const arr_desc *ap); | ||
|
|
||
| // allocate element of CeanReadRanges type initialized | ||
| // to read consequently contiguous ranges described by "ap" argument | ||
| CeanReadRanges * init_read_ranges_arr_desc(const arr_desc *ap); | ||
|
|
||
| // check if ranges described by 1 argument could be transfered into ranges | ||
| // described by 2-nd one | ||
| bool cean_ranges_match( | ||
| CeanReadRanges * read_rng1, | ||
| CeanReadRanges * read_rng2 | ||
| ); | ||
|
|
||
| // first argument - returned value by call to init_read_ranges_arr_desc. | ||
| // returns true if offset and length of next range is set successfuly. | ||
| // returns false if the ranges is over. | ||
| bool get_next_range( | ||
| CeanReadRanges * read_rng, | ||
| int64_t *offset | ||
| ); | ||
|
|
||
| // returns number of transfered bytes | ||
| int64_t cean_get_transf_size(CeanReadRanges * read_rng); | ||
|
|
||
| #if OFFLOAD_DEBUG > 0 | ||
| // prints array descriptor contents to stderr | ||
| void __arr_desc_dump( | ||
| const char *spaces, | ||
| const char *name, | ||
| const arr_desc *adp, | ||
| bool dereference); | ||
| #else | ||
| #define __arr_desc_dump( | ||
| spaces, | ||
| name, | ||
| adp, | ||
| dereference) | ||
| #endif // OFFLOAD_DEBUG | ||
|
|
||
| #endif // CEAN_UTIL_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,350 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| // The COI host interface | ||
|
|
||
| #include "coi_client.h" | ||
| #include "../offload_common.h" | ||
|
|
||
| namespace COI { | ||
|
|
||
| #define COI_VERSION1 "COI_1.0" | ||
| #define COI_VERSION2 "COI_2.0" | ||
|
|
||
| bool is_available; | ||
| static void* lib_handle; | ||
|
|
||
| // pointers to functions from COI library | ||
| COIRESULT (*EngineGetCount)(COI_ISA_TYPE, uint32_t*); | ||
| COIRESULT (*EngineGetHandle)(COI_ISA_TYPE, uint32_t, COIENGINE*); | ||
|
|
||
| COIRESULT (*ProcessCreateFromMemory)(COIENGINE, const char*, const void*, | ||
| uint64_t, int, const char**, uint8_t, | ||
| const char**, uint8_t, const char*, | ||
| uint64_t, const char*, const char*, | ||
| uint64_t, COIPROCESS*); | ||
| COIRESULT (*ProcessDestroy)(COIPROCESS, int32_t, uint8_t, int8_t*, uint32_t*); | ||
| COIRESULT (*ProcessGetFunctionHandles)(COIPROCESS, uint32_t, const char**, | ||
| COIFUNCTION*); | ||
| COIRESULT (*ProcessLoadLibraryFromMemory)(COIPROCESS, const void*, uint64_t, | ||
| const char*, const char*, | ||
| const char*, uint64_t, uint32_t, | ||
| COILIBRARY*); | ||
| COIRESULT (*ProcessRegisterLibraries)(uint32_t, const void**, const uint64_t*, | ||
| const char**, const uint64_t*); | ||
|
|
||
| COIRESULT (*PipelineCreate)(COIPROCESS, COI_CPU_MASK, uint32_t, COIPIPELINE*); | ||
| COIRESULT (*PipelineDestroy)(COIPIPELINE); | ||
| COIRESULT (*PipelineRunFunction)(COIPIPELINE, COIFUNCTION, uint32_t, | ||
| const COIBUFFER*, const COI_ACCESS_FLAGS*, | ||
| uint32_t, const COIEVENT*, const void*, | ||
| uint16_t, void*, uint16_t, COIEVENT*); | ||
|
|
||
| COIRESULT (*BufferCreate)(uint64_t, COI_BUFFER_TYPE, uint32_t, const void*, | ||
| uint32_t, const COIPROCESS*, COIBUFFER*); | ||
| COIRESULT (*BufferCreateFromMemory)(uint64_t, COI_BUFFER_TYPE, uint32_t, | ||
| void*, uint32_t, const COIPROCESS*, | ||
| COIBUFFER*); | ||
| COIRESULT (*BufferDestroy)(COIBUFFER); | ||
| COIRESULT (*BufferMap)(COIBUFFER, uint64_t, uint64_t, COI_MAP_TYPE, uint32_t, | ||
| const COIEVENT*, COIEVENT*, COIMAPINSTANCE*, void**); | ||
| COIRESULT (*BufferUnmap)(COIMAPINSTANCE, uint32_t, const COIEVENT*, COIEVENT*); | ||
| COIRESULT (*BufferWrite)(COIBUFFER, uint64_t, const void*, uint64_t, | ||
| COI_COPY_TYPE, uint32_t, const COIEVENT*, COIEVENT*); | ||
| COIRESULT (*BufferRead)(COIBUFFER, uint64_t, void*, uint64_t, COI_COPY_TYPE, | ||
| uint32_t, const COIEVENT*, COIEVENT*); | ||
| COIRESULT (*BufferCopy)(COIBUFFER, COIBUFFER, uint64_t, uint64_t, uint64_t, | ||
| COI_COPY_TYPE, uint32_t, const COIEVENT*, COIEVENT*); | ||
| COIRESULT (*BufferGetSinkAddress)(COIBUFFER, uint64_t*); | ||
| COIRESULT (*BufferSetState)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE, | ||
| COI_BUFFER_MOVE_FLAG, uint32_t, | ||
| const COIEVENT*, COIEVENT*); | ||
|
|
||
| COIRESULT (*EventWait)(uint16_t, const COIEVENT*, int32_t, uint8_t, uint32_t*, | ||
| uint32_t*); | ||
|
|
||
| uint64_t (*PerfGetCycleFrequency)(void); | ||
|
|
||
| bool init(void) | ||
| { | ||
| #ifndef TARGET_WINNT | ||
| const char *lib_name = "libcoi_host.so.0"; | ||
| #else // TARGET_WINNT | ||
| const char *lib_name = "coi_host.dll"; | ||
| #endif // TARGET_WINNT | ||
|
|
||
| OFFLOAD_DEBUG_TRACE(2, "Loading COI library %s ...\n", lib_name); | ||
| lib_handle = DL_open(lib_name); | ||
| if (lib_handle == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to load the library\n"); | ||
| return false; | ||
| } | ||
|
|
||
| EngineGetCount = | ||
| (COIRESULT (*)(COI_ISA_TYPE, uint32_t*)) | ||
| DL_sym(lib_handle, "COIEngineGetCount", COI_VERSION1); | ||
| if (EngineGetCount == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIEngineGetCount"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| EngineGetHandle = | ||
| (COIRESULT (*)(COI_ISA_TYPE, uint32_t, COIENGINE*)) | ||
| DL_sym(lib_handle, "COIEngineGetHandle", COI_VERSION1); | ||
| if (EngineGetHandle == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIEngineGetHandle"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| ProcessCreateFromMemory = | ||
| (COIRESULT (*)(COIENGINE, const char*, const void*, uint64_t, int, | ||
| const char**, uint8_t, const char**, uint8_t, | ||
| const char*, uint64_t, const char*, const char*, | ||
| uint64_t, COIPROCESS*)) | ||
| DL_sym(lib_handle, "COIProcessCreateFromMemory", COI_VERSION1); | ||
| if (ProcessCreateFromMemory == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIProcessCreateFromMemory"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| ProcessDestroy = | ||
| (COIRESULT (*)(COIPROCESS, int32_t, uint8_t, int8_t*, | ||
| uint32_t*)) | ||
| DL_sym(lib_handle, "COIProcessDestroy", COI_VERSION1); | ||
| if (ProcessDestroy == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIProcessDestroy"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| ProcessGetFunctionHandles = | ||
| (COIRESULT (*)(COIPROCESS, uint32_t, const char**, COIFUNCTION*)) | ||
| DL_sym(lib_handle, "COIProcessGetFunctionHandles", COI_VERSION1); | ||
| if (ProcessGetFunctionHandles == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIProcessGetFunctionHandles"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| ProcessLoadLibraryFromMemory = | ||
| (COIRESULT (*)(COIPROCESS, const void*, uint64_t, const char*, | ||
| const char*, const char*, uint64_t, uint32_t, | ||
| COILIBRARY*)) | ||
| DL_sym(lib_handle, "COIProcessLoadLibraryFromMemory", COI_VERSION2); | ||
| if (ProcessLoadLibraryFromMemory == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIProcessLoadLibraryFromMemory"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| ProcessRegisterLibraries = | ||
| (COIRESULT (*)(uint32_t, const void**, const uint64_t*, const char**, | ||
| const uint64_t*)) | ||
| DL_sym(lib_handle, "COIProcessRegisterLibraries", COI_VERSION1); | ||
| if (ProcessRegisterLibraries == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIProcessRegisterLibraries"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| PipelineCreate = | ||
| (COIRESULT (*)(COIPROCESS, COI_CPU_MASK, uint32_t, COIPIPELINE*)) | ||
| DL_sym(lib_handle, "COIPipelineCreate", COI_VERSION1); | ||
| if (PipelineCreate == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIPipelineCreate"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| PipelineDestroy = | ||
| (COIRESULT (*)(COIPIPELINE)) | ||
| DL_sym(lib_handle, "COIPipelineDestroy", COI_VERSION1); | ||
| if (PipelineDestroy == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIPipelineDestroy"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| PipelineRunFunction = | ||
| (COIRESULT (*)(COIPIPELINE, COIFUNCTION, uint32_t, const COIBUFFER*, | ||
| const COI_ACCESS_FLAGS*, uint32_t, const COIEVENT*, | ||
| const void*, uint16_t, void*, uint16_t, COIEVENT*)) | ||
| DL_sym(lib_handle, "COIPipelineRunFunction", COI_VERSION1); | ||
| if (PipelineRunFunction == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIPipelineRunFunction"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferCreate = | ||
| (COIRESULT (*)(uint64_t, COI_BUFFER_TYPE, uint32_t, const void*, | ||
| uint32_t, const COIPROCESS*, COIBUFFER*)) | ||
| DL_sym(lib_handle, "COIBufferCreate", COI_VERSION1); | ||
| if (BufferCreate == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferCreate"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferCreateFromMemory = | ||
| (COIRESULT (*)(uint64_t, COI_BUFFER_TYPE, uint32_t, void*, | ||
| uint32_t, const COIPROCESS*, COIBUFFER*)) | ||
| DL_sym(lib_handle, "COIBufferCreateFromMemory", COI_VERSION1); | ||
| if (BufferCreateFromMemory == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferCreateFromMemory"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferDestroy = | ||
| (COIRESULT (*)(COIBUFFER)) | ||
| DL_sym(lib_handle, "COIBufferDestroy", COI_VERSION1); | ||
| if (BufferDestroy == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferDestroy"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferMap = | ||
| (COIRESULT (*)(COIBUFFER, uint64_t, uint64_t, COI_MAP_TYPE, uint32_t, | ||
| const COIEVENT*, COIEVENT*, COIMAPINSTANCE*, | ||
| void**)) | ||
| DL_sym(lib_handle, "COIBufferMap", COI_VERSION1); | ||
| if (BufferMap == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferMap"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferUnmap = | ||
| (COIRESULT (*)(COIMAPINSTANCE, uint32_t, const COIEVENT*, | ||
| COIEVENT*)) | ||
| DL_sym(lib_handle, "COIBufferUnmap", COI_VERSION1); | ||
| if (BufferUnmap == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferUnmap"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferWrite = | ||
| (COIRESULT (*)(COIBUFFER, uint64_t, const void*, uint64_t, | ||
| COI_COPY_TYPE, uint32_t, const COIEVENT*, | ||
| COIEVENT*)) | ||
| DL_sym(lib_handle, "COIBufferWrite", COI_VERSION1); | ||
| if (BufferWrite == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferWrite"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferRead = | ||
| (COIRESULT (*)(COIBUFFER, uint64_t, void*, uint64_t, | ||
| COI_COPY_TYPE, uint32_t, | ||
| const COIEVENT*, COIEVENT*)) | ||
| DL_sym(lib_handle, "COIBufferRead", COI_VERSION1); | ||
| if (BufferRead == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferRead"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferCopy = | ||
| (COIRESULT (*)(COIBUFFER, COIBUFFER, uint64_t, uint64_t, uint64_t, | ||
| COI_COPY_TYPE, uint32_t, const COIEVENT*, | ||
| COIEVENT*)) | ||
| DL_sym(lib_handle, "COIBufferCopy", COI_VERSION1); | ||
| if (BufferCopy == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferCopy"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferGetSinkAddress = | ||
| (COIRESULT (*)(COIBUFFER, uint64_t*)) | ||
| DL_sym(lib_handle, "COIBufferGetSinkAddress", COI_VERSION1); | ||
| if (BufferGetSinkAddress == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferGetSinkAddress"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| BufferSetState = | ||
| (COIRESULT(*)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE, | ||
| COI_BUFFER_MOVE_FLAG, uint32_t, const COIEVENT*, | ||
| COIEVENT*)) | ||
| DL_sym(lib_handle, "COIBufferSetState", COI_VERSION1); | ||
| if (BufferSetState == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIBufferSetState"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| EventWait = | ||
| (COIRESULT (*)(uint16_t, const COIEVENT*, int32_t, uint8_t, | ||
| uint32_t*, uint32_t*)) | ||
| DL_sym(lib_handle, "COIEventWait", COI_VERSION1); | ||
| if (EventWait == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIEventWait"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| PerfGetCycleFrequency = | ||
| (uint64_t (*)(void)) | ||
| DL_sym(lib_handle, "COIPerfGetCycleFrequency", COI_VERSION1); | ||
| if (PerfGetCycleFrequency == 0) { | ||
| OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n", | ||
| "COIPerfGetCycleFrequency"); | ||
| fini(); | ||
| return false; | ||
| } | ||
|
|
||
| is_available = true; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void fini(void) | ||
| { | ||
| is_available = false; | ||
|
|
||
| if (lib_handle != 0) { | ||
| #ifndef TARGET_WINNT | ||
| DL_close(lib_handle); | ||
| #endif // TARGET_WINNT | ||
| lib_handle = 0; | ||
| } | ||
| } | ||
|
|
||
| } // namespace COI |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| // The interface betwen offload library and the COI API on the host | ||
|
|
||
| #ifndef COI_CLIENT_H_INCLUDED | ||
| #define COI_CLIENT_H_INCLUDED | ||
|
|
||
| #include <common/COIPerf_common.h> | ||
| #include <source/COIEngine_source.h> | ||
| #include <source/COIProcess_source.h> | ||
| #include <source/COIPipeline_source.h> | ||
| #include <source/COIBuffer_source.h> | ||
| #include <source/COIEvent_source.h> | ||
|
|
||
| #include <string.h> | ||
|
|
||
| #include "../liboffload_error_codes.h" | ||
| #include "../offload_util.h" | ||
|
|
||
| #define MIC_ENGINES_MAX 128 | ||
|
|
||
| #if MIC_ENGINES_MAX < COI_MAX_ISA_MIC_DEVICES | ||
| #error MIC_ENGINES_MAX need to be increased | ||
| #endif | ||
|
|
||
| // COI library interface | ||
| namespace COI { | ||
|
|
||
| extern bool init(void); | ||
| extern void fini(void); | ||
|
|
||
| extern bool is_available; | ||
|
|
||
| // pointers to functions from COI library | ||
| extern COIRESULT (*EngineGetCount)(COI_ISA_TYPE, uint32_t*); | ||
| extern COIRESULT (*EngineGetHandle)(COI_ISA_TYPE, uint32_t, COIENGINE*); | ||
|
|
||
| extern COIRESULT (*ProcessCreateFromMemory)(COIENGINE, const char*, | ||
| const void*, uint64_t, int, | ||
| const char**, uint8_t, | ||
| const char**, uint8_t, | ||
| const char*, uint64_t, | ||
| const char*, | ||
| const char*, uint64_t, | ||
| COIPROCESS*); | ||
| extern COIRESULT (*ProcessDestroy)(COIPROCESS, int32_t, uint8_t, | ||
| int8_t*, uint32_t*); | ||
| extern COIRESULT (*ProcessGetFunctionHandles)(COIPROCESS, uint32_t, | ||
| const char**, | ||
| COIFUNCTION*); | ||
| extern COIRESULT (*ProcessLoadLibraryFromMemory)(COIPROCESS, | ||
| const void*, | ||
| uint64_t, | ||
| const char*, | ||
| const char*, | ||
| const char*, | ||
| uint64_t, | ||
| uint32_t, | ||
| COILIBRARY*); | ||
| extern COIRESULT (*ProcessRegisterLibraries)(uint32_t, | ||
| const void**, | ||
| const uint64_t*, | ||
| const char**, | ||
| const uint64_t*); | ||
|
|
||
| extern COIRESULT (*PipelineCreate)(COIPROCESS, COI_CPU_MASK, uint32_t, | ||
| COIPIPELINE*); | ||
| extern COIRESULT (*PipelineDestroy)(COIPIPELINE); | ||
| extern COIRESULT (*PipelineRunFunction)(COIPIPELINE, COIFUNCTION, | ||
| uint32_t, const COIBUFFER*, | ||
| const COI_ACCESS_FLAGS*, | ||
| uint32_t, const COIEVENT*, | ||
| const void*, uint16_t, void*, | ||
| uint16_t, COIEVENT*); | ||
|
|
||
| extern COIRESULT (*BufferCreate)(uint64_t, COI_BUFFER_TYPE, uint32_t, | ||
| const void*, uint32_t, | ||
| const COIPROCESS*, COIBUFFER*); | ||
| extern COIRESULT (*BufferCreateFromMemory)(uint64_t, COI_BUFFER_TYPE, | ||
| uint32_t, void*, | ||
| uint32_t, const COIPROCESS*, | ||
| COIBUFFER*); | ||
| extern COIRESULT (*BufferDestroy)(COIBUFFER); | ||
| extern COIRESULT (*BufferMap)(COIBUFFER, uint64_t, uint64_t, | ||
| COI_MAP_TYPE, uint32_t, const COIEVENT*, | ||
| COIEVENT*, COIMAPINSTANCE*, void**); | ||
| extern COIRESULT (*BufferUnmap)(COIMAPINSTANCE, uint32_t, | ||
| const COIEVENT*, COIEVENT*); | ||
| extern COIRESULT (*BufferWrite)(COIBUFFER, uint64_t, const void*, | ||
| uint64_t, COI_COPY_TYPE, uint32_t, | ||
| const COIEVENT*, COIEVENT*); | ||
| extern COIRESULT (*BufferRead)(COIBUFFER, uint64_t, void*, uint64_t, | ||
| COI_COPY_TYPE, uint32_t, | ||
| const COIEVENT*, COIEVENT*); | ||
| extern COIRESULT (*BufferCopy)(COIBUFFER, COIBUFFER, uint64_t, uint64_t, | ||
| uint64_t, COI_COPY_TYPE, uint32_t, | ||
| const COIEVENT*, COIEVENT*); | ||
| extern COIRESULT (*BufferGetSinkAddress)(COIBUFFER, uint64_t*); | ||
| extern COIRESULT (*BufferSetState)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE, | ||
| COI_BUFFER_MOVE_FLAG, uint32_t, | ||
| const COIEVENT*, COIEVENT*); | ||
|
|
||
| extern COIRESULT (*EventWait)(uint16_t, const COIEVENT*, int32_t, | ||
| uint8_t, uint32_t*, uint32_t*); | ||
|
|
||
| extern uint64_t (*PerfGetCycleFrequency)(void); | ||
|
|
||
| } // namespace COI | ||
|
|
||
| #endif // COI_CLIENT_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| // The COI interface on the target | ||
|
|
||
| #include "coi_server.h" | ||
|
|
||
| #include "../offload_target.h" | ||
| #include "../offload_timer.h" | ||
| #ifdef MYO_SUPPORT | ||
| #include "../offload_myo_target.h" // for __offload_myoLibInit/Fini | ||
| #endif // MYO_SUPPORT | ||
|
|
||
| COINATIVELIBEXPORT | ||
| void server_compute( | ||
| uint32_t buffer_count, | ||
| void** buffers, | ||
| uint64_t* buffers_len, | ||
| void* misc_data, | ||
| uint16_t misc_data_len, | ||
| void* return_data, | ||
| uint16_t return_data_len | ||
| ) | ||
| { | ||
| OffloadDescriptor::offload(buffer_count, buffers, | ||
| misc_data, misc_data_len, | ||
| return_data, return_data_len); | ||
| } | ||
|
|
||
| COINATIVELIBEXPORT | ||
| void server_init( | ||
| uint32_t buffer_count, | ||
| void** buffers, | ||
| uint64_t* buffers_len, | ||
| void* misc_data, | ||
| uint16_t misc_data_len, | ||
| void* return_data, | ||
| uint16_t return_data_len | ||
| ) | ||
| { | ||
| struct init_data { | ||
| int device_index; | ||
| int devices_total; | ||
| int console_level; | ||
| int offload_report_level; | ||
| } *data = (struct init_data*) misc_data; | ||
|
|
||
| // set device index and number of total devices | ||
| mic_index = data->device_index; | ||
| mic_engines_total = data->devices_total; | ||
|
|
||
| // initialize trace level | ||
| console_enabled = data->console_level; | ||
| offload_report_level = data->offload_report_level; | ||
|
|
||
| // return back the process id | ||
| *((pid_t*) return_data) = getpid(); | ||
| } | ||
|
|
||
| COINATIVELIBEXPORT | ||
| void server_var_table_size( | ||
| uint32_t buffer_count, | ||
| void** buffers, | ||
| uint64_t* buffers_len, | ||
| void* misc_data, | ||
| uint16_t misc_data_len, | ||
| void* return_data, | ||
| uint16_t return_data_len | ||
| ) | ||
| { | ||
| struct Params { | ||
| int64_t nelems; | ||
| int64_t length; | ||
| } *params; | ||
|
|
||
| params = static_cast<Params*>(return_data); | ||
| params->length = __offload_vars.table_size(params->nelems); | ||
| } | ||
|
|
||
| COINATIVELIBEXPORT | ||
| void server_var_table_copy( | ||
| uint32_t buffer_count, | ||
| void** buffers, | ||
| uint64_t* buffers_len, | ||
| void* misc_data, | ||
| uint16_t misc_data_len, | ||
| void* return_data, | ||
| uint16_t return_data_len | ||
| ) | ||
| { | ||
| __offload_vars.table_copy(buffers[0], *static_cast<int64_t*>(misc_data)); | ||
| } | ||
|
|
||
| #ifdef MYO_SUPPORT | ||
| // temporary workaround for blocking behavior of myoiLibInit/Fini calls | ||
| COINATIVELIBEXPORT | ||
| void server_myoinit( | ||
| uint32_t buffer_count, | ||
| void** buffers, | ||
| uint64_t* buffers_len, | ||
| void* misc_data, | ||
| uint16_t misc_data_len, | ||
| void* return_data, | ||
| uint16_t return_data_len | ||
| ) | ||
| { | ||
| __offload_myoLibInit(); | ||
| } | ||
|
|
||
| COINATIVELIBEXPORT | ||
| void server_myofini( | ||
| uint32_t buffer_count, | ||
| void** buffers, | ||
| uint64_t* buffers_len, | ||
| void* misc_data, | ||
| uint16_t misc_data_len, | ||
| void* return_data, | ||
| uint16_t return_data_len | ||
| ) | ||
| { | ||
| __offload_myoLibFini(); | ||
| } | ||
| #endif // MYO_SUPPORT |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| //The interface betwen offload library and the COI API on the target. | ||
|
|
||
| #ifndef COI_SERVER_H_INCLUDED | ||
| #define COI_SERVER_H_INCLUDED | ||
|
|
||
| #include <common/COIEngine_common.h> | ||
| #include <common/COIPerf_common.h> | ||
| #include <sink/COIProcess_sink.h> | ||
| #include <sink/COIPipeline_sink.h> | ||
| #include <sink/COIBuffer_sink.h> | ||
| #include <list> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <unistd.h> | ||
| #include "../liboffload_error_codes.h" | ||
|
|
||
| // wrappers for COI API | ||
| #define PipelineStartExecutingRunFunctions() \ | ||
| { \ | ||
| COIRESULT res = COIPipelineStartExecutingRunFunctions(); \ | ||
| if (res != COI_SUCCESS) { \ | ||
| LIBOFFLOAD_ERROR(c_pipeline_start_run_funcs, mic_index, res); \ | ||
| exit(1); \ | ||
| } \ | ||
| } | ||
|
|
||
| #define ProcessWaitForShutdown() \ | ||
| { \ | ||
| COIRESULT res = COIProcessWaitForShutdown(); \ | ||
| if (res != COI_SUCCESS) { \ | ||
| LIBOFFLOAD_ERROR(c_process_wait_shutdown, mic_index, res); \ | ||
| exit(1); \ | ||
| } \ | ||
| } | ||
|
|
||
| #define BufferAddRef(buf) \ | ||
| { \ | ||
| COIRESULT res = COIBufferAddRef(buf); \ | ||
| if (res != COI_SUCCESS) { \ | ||
| LIBOFFLOAD_ERROR(c_buf_add_ref, mic_index, res); \ | ||
| exit(1); \ | ||
| } \ | ||
| } | ||
|
|
||
| #define BufferReleaseRef(buf) \ | ||
| { \ | ||
| COIRESULT res = COIBufferReleaseRef(buf); \ | ||
| if (res != COI_SUCCESS) { \ | ||
| LIBOFFLOAD_ERROR(c_buf_release_ref, mic_index, res); \ | ||
| exit(1); \ | ||
| } \ | ||
| } | ||
|
|
||
| #define EngineGetIndex(index) \ | ||
| { \ | ||
| COI_ISA_TYPE isa_type; \ | ||
| COIRESULT res = COIEngineGetIndex(&isa_type, index); \ | ||
| if (res != COI_SUCCESS) { \ | ||
| LIBOFFLOAD_ERROR(c_get_engine_index, mic_index, res); \ | ||
| exit(1); \ | ||
| } \ | ||
| } | ||
|
|
||
| #endif // COI_SERVER_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,323 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #include "compiler_if_host.h" | ||
|
|
||
| #include <malloc.h> | ||
| #ifndef TARGET_WINNT | ||
| #include <alloca.h> | ||
| #endif // TARGET_WINNT | ||
|
|
||
| // Global counter on host. | ||
| // This variable is used if P2OPT_offload_do_data_persistence == 2. | ||
| // The variable used to identify offload constructs contained in one procedure. | ||
| // Increment of OFFLOAD_CALL_COUNT is inserted at entries of HOST routines with | ||
| // offload constructs. | ||
| static int offload_call_count = 0; | ||
|
|
||
| extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE( | ||
| TARGET_TYPE target_type, | ||
| int target_number, | ||
| int is_optional, | ||
| _Offload_status* status, | ||
| const char* file, | ||
| uint64_t line | ||
| ) | ||
| { | ||
| bool retval; | ||
| OFFLOAD ofld; | ||
|
|
||
| // initialize status | ||
| if (status != 0) { | ||
| status->result = OFFLOAD_UNAVAILABLE; | ||
| status->device_number = -1; | ||
| status->data_sent = 0; | ||
| status->data_received = 0; | ||
| } | ||
|
|
||
| // make sure libray is initialized | ||
| retval = __offload_init_library(); | ||
|
|
||
| // OFFLOAD_TIMER_INIT must follow call to __offload_init_library | ||
| OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line); | ||
|
|
||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload); | ||
|
|
||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize); | ||
|
|
||
| // initalize all devices is init_type is on_offload_all | ||
| if (retval && __offload_init_type == c_init_on_offload_all) { | ||
| for (int i = 0; i < mic_engines_total; i++) { | ||
| mic_engines[i].init(); | ||
| } | ||
| } | ||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize); | ||
|
|
||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire); | ||
|
|
||
| if (target_type == TARGET_HOST) { | ||
| // Host always available | ||
| retval = true; | ||
| } | ||
| else if (target_type == TARGET_MIC) { | ||
| if (target_number >= -1) { | ||
| if (retval) { | ||
| if (target_number >= 0) { | ||
| // User provided the device number | ||
| target_number = target_number % mic_engines_total; | ||
| } | ||
| else { | ||
| // use device 0 | ||
| target_number = 0; | ||
| } | ||
|
|
||
| // reserve device in ORSL | ||
| if (is_optional) { | ||
| if (!ORSL::try_reserve(target_number)) { | ||
| target_number = -1; | ||
| } | ||
| } | ||
| else { | ||
| if (!ORSL::reserve(target_number)) { | ||
| target_number = -1; | ||
| } | ||
| } | ||
|
|
||
| // initialize device | ||
| if (target_number >= 0 && | ||
| __offload_init_type == c_init_on_offload) { | ||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize); | ||
| mic_engines[target_number].init(); | ||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize); | ||
| } | ||
| } | ||
| else { | ||
| // fallback to CPU | ||
| target_number = -1; | ||
| } | ||
|
|
||
| if (target_number < 0 || !retval) { | ||
| if (!is_optional && status == 0) { | ||
| LIBOFFLOAD_ERROR(c_device_is_not_available); | ||
| exit(1); | ||
| } | ||
|
|
||
| retval = false; | ||
| } | ||
| } | ||
| else { | ||
| LIBOFFLOAD_ERROR(c_invalid_device_number); | ||
| exit(1); | ||
| } | ||
| } | ||
|
|
||
| if (retval) { | ||
| ofld = new OffloadDescriptor(target_number, status, | ||
| !is_optional, false, timer_data); | ||
| OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number); | ||
| Offload_Report_Prolog(timer_data); | ||
| OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start, | ||
| "Starting offload: target_type = %d, " | ||
| "number = %d, is_optional = %d\n", | ||
| target_type, target_number, is_optional); | ||
|
|
||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire); | ||
| } | ||
| else { | ||
| ofld = NULL; | ||
|
|
||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire); | ||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_total_offload); | ||
| offload_report_free_data(timer_data); | ||
| } | ||
|
|
||
| return ofld; | ||
| } | ||
|
|
||
| extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE1( | ||
| const int* device_num, | ||
| const char* file, | ||
| uint64_t line | ||
| ) | ||
| { | ||
| int target_number; | ||
|
|
||
| // make sure libray is initialized and at least one device is available | ||
| if (!__offload_init_library()) { | ||
| LIBOFFLOAD_ERROR(c_device_is_not_available); | ||
| exit(1); | ||
| } | ||
|
|
||
| // OFFLOAD_TIMER_INIT must follow call to __offload_init_library | ||
|
|
||
| OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line); | ||
|
|
||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload); | ||
|
|
||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize); | ||
|
|
||
| if (__offload_init_type == c_init_on_offload_all) { | ||
| for (int i = 0; i < mic_engines_total; i++) { | ||
| mic_engines[i].init(); | ||
| } | ||
| } | ||
|
|
||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize); | ||
|
|
||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire); | ||
|
|
||
| // use default device number if it is not provided | ||
| if (device_num != 0) { | ||
| target_number = *device_num; | ||
| } | ||
| else { | ||
| target_number = __omp_device_num; | ||
| } | ||
|
|
||
| // device number should be a non-negative integer value | ||
| if (target_number < 0) { | ||
| LIBOFFLOAD_ERROR(c_omp_invalid_device_num); | ||
| exit(1); | ||
| } | ||
|
|
||
| // should we do this for OpenMP? | ||
| target_number %= mic_engines_total; | ||
|
|
||
| // reserve device in ORSL | ||
| if (!ORSL::reserve(target_number)) { | ||
| LIBOFFLOAD_ERROR(c_device_is_not_available); | ||
| exit(1); | ||
| } | ||
|
|
||
| // initialize device(s) | ||
| OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize); | ||
|
|
||
| if (__offload_init_type == c_init_on_offload) { | ||
| mic_engines[target_number].init(); | ||
| } | ||
|
|
||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize); | ||
|
|
||
| OFFLOAD ofld = | ||
| new OffloadDescriptor(target_number, 0, true, true, timer_data); | ||
|
|
||
| OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number); | ||
|
|
||
| Offload_Report_Prolog(timer_data); | ||
|
|
||
| OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start, | ||
| "Starting OpenMP offload, device = %d\n", | ||
| target_number); | ||
|
|
||
| OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire); | ||
|
|
||
| return ofld; | ||
| } | ||
|
|
||
| int offload_offload_wrap( | ||
| OFFLOAD ofld, | ||
| const char *name, | ||
| int is_empty, | ||
| int num_vars, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2, | ||
| int num_waits, | ||
| const void **waits, | ||
| const void **signal, | ||
| int entry_id, | ||
| const void *stack_addr | ||
| ) | ||
| { | ||
| bool ret = ofld->offload(name, is_empty, vars, vars2, num_vars, | ||
| waits, num_waits, signal, entry_id, stack_addr); | ||
| if (!ret || signal == 0) { | ||
| delete ofld; | ||
| } | ||
| return ret; | ||
| } | ||
|
|
||
| extern "C" int OFFLOAD_OFFLOAD1( | ||
| OFFLOAD ofld, | ||
| const char *name, | ||
| int is_empty, | ||
| int num_vars, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2, | ||
| int num_waits, | ||
| const void **waits, | ||
| const void **signal | ||
| ) | ||
| { | ||
| return offload_offload_wrap(ofld, name, is_empty, | ||
| num_vars, vars, vars2, | ||
| num_waits, waits, | ||
| signal, NULL, NULL); | ||
| } | ||
|
|
||
| extern "C" int OFFLOAD_OFFLOAD2( | ||
| OFFLOAD ofld, | ||
| const char *name, | ||
| int is_empty, | ||
| int num_vars, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2, | ||
| int num_waits, | ||
| const void** waits, | ||
| const void** signal, | ||
| int entry_id, | ||
| const void *stack_addr | ||
| ) | ||
| { | ||
| return offload_offload_wrap(ofld, name, is_empty, | ||
| num_vars, vars, vars2, | ||
| num_waits, waits, | ||
| signal, entry_id, stack_addr); | ||
| } | ||
|
|
||
| extern "C" int OFFLOAD_OFFLOAD( | ||
| OFFLOAD ofld, | ||
| const char *name, | ||
| int is_empty, | ||
| int num_vars, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2, | ||
| int num_waits, | ||
| const void **waits, | ||
| const void *signal, | ||
| int entry_id, | ||
| const void *stack_addr | ||
| ) | ||
| { | ||
| // signal is passed by reference now | ||
| const void **signal_new = (signal != 0) ? &signal : 0; | ||
| const void **waits_new = 0; | ||
| int num_waits_new = 0; | ||
|
|
||
| // remove NULL values from the list of signals to wait for | ||
| if (num_waits > 0) { | ||
| waits_new = (const void**) alloca(sizeof(void*) * num_waits); | ||
| for (int i = 0; i < num_waits; i++) { | ||
| if (waits[i] != 0) { | ||
| waits_new[num_waits_new++] = waits[i]; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return OFFLOAD_OFFLOAD1(ofld, name, is_empty, | ||
| num_vars, vars, vars2, | ||
| num_waits_new, waits_new, | ||
| signal_new); | ||
| } | ||
|
|
||
| extern "C" int OFFLOAD_CALL_COUNT() | ||
| { | ||
| offload_call_count++; | ||
| return offload_call_count; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| /*! \file | ||
| \brief The interface between compiler-generated host code and runtime library | ||
| */ | ||
|
|
||
| #ifndef COMPILER_IF_HOST_H_INCLUDED | ||
| #define COMPILER_IF_HOST_H_INCLUDED | ||
|
|
||
| #include "offload_host.h" | ||
|
|
||
| #define OFFLOAD_TARGET_ACQUIRE OFFLOAD_PREFIX(target_acquire) | ||
| #define OFFLOAD_TARGET_ACQUIRE1 OFFLOAD_PREFIX(target_acquire1) | ||
| #define OFFLOAD_OFFLOAD OFFLOAD_PREFIX(offload) | ||
| #define OFFLOAD_OFFLOAD1 OFFLOAD_PREFIX(offload1) | ||
| #define OFFLOAD_OFFLOAD2 OFFLOAD_PREFIX(offload2) | ||
| #define OFFLOAD_CALL_COUNT OFFLOAD_PREFIX(offload_call_count) | ||
|
|
||
|
|
||
| /*! \fn OFFLOAD_TARGET_ACQUIRE | ||
| \brief Attempt to acquire the target. | ||
| \param target_type The type of target. | ||
| \param target_number The device number. | ||
| \param is_optional Whether CPU fall-back is allowed. | ||
| \param status Address of variable to hold offload status. | ||
| \param file Filename in which this offload occurred. | ||
| \param line Line number in the file where this offload occurred. | ||
| */ | ||
| extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE( | ||
| TARGET_TYPE target_type, | ||
| int target_number, | ||
| int is_optional, | ||
| _Offload_status* status, | ||
| const char* file, | ||
| uint64_t line | ||
| ); | ||
|
|
||
| /*! \fn OFFLOAD_TARGET_ACQUIRE1 | ||
| \brief Acquire the target for offload (OpenMP). | ||
| \param device_number Device number or null if not specified. | ||
| \param file Filename in which this offload occurred | ||
| \param line Line number in the file where this offload occurred. | ||
| */ | ||
| extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE1( | ||
| const int* device_number, | ||
| const char* file, | ||
| uint64_t line | ||
| ); | ||
|
|
||
| /*! \fn OFFLOAD_OFFLOAD1 | ||
| \brief Run function on target using interface for old data persistence. | ||
| \param o Offload descriptor created by OFFLOAD_TARGET_ACQUIRE. | ||
| \param name Name of offload entry point. | ||
| \param is_empty If no code to execute (e.g. offload_transfer) | ||
| \param num_vars Number of variable descriptors. | ||
| \param vars Pointer to VarDesc array. | ||
| \param vars2 Pointer to VarDesc2 array. | ||
| \param num_waits Number of "wait" values. | ||
| \param waits Pointer to array of wait values. | ||
| \param signal Pointer to signal value or NULL. | ||
| */ | ||
| extern "C" int OFFLOAD_OFFLOAD1( | ||
| OFFLOAD o, | ||
| const char *name, | ||
| int is_empty, | ||
| int num_vars, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2, | ||
| int num_waits, | ||
| const void** waits, | ||
| const void** signal | ||
| ); | ||
|
|
||
| /*! \fn OFFLOAD_OFFLOAD2 | ||
| \brief Run function on target using interface for new data persistence. | ||
| \param o Offload descriptor created by OFFLOAD_TARGET_ACQUIRE. | ||
| \param name Name of offload entry point. | ||
| \param is_empty If no code to execute (e.g. offload_transfer) | ||
| \param num_vars Number of variable descriptors. | ||
| \param vars Pointer to VarDesc array. | ||
| \param vars2 Pointer to VarDesc2 array. | ||
| \param num_waits Number of "wait" values. | ||
| \param waits Pointer to array of wait values. | ||
| \param signal Pointer to signal value or NULL. | ||
| \param entry_id A signature for the function doing the offload. | ||
| \param stack_addr The stack frame address of the function doing offload. | ||
| */ | ||
| extern "C" int OFFLOAD_OFFLOAD2( | ||
| OFFLOAD o, | ||
| const char *name, | ||
| int is_empty, | ||
| int num_vars, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2, | ||
| int num_waits, | ||
| const void** waits, | ||
| const void** signal, | ||
| int entry_id, | ||
| const void *stack_addr | ||
| ); | ||
|
|
||
| // Run function on target (obsolete). | ||
| // @param o OFFLOAD object | ||
| // @param name function name | ||
| extern "C" int OFFLOAD_OFFLOAD( | ||
| OFFLOAD o, | ||
| const char *name, | ||
| int is_empty, | ||
| int num_vars, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2, | ||
| int num_waits, | ||
| const void** waits, | ||
| const void* signal, | ||
| int entry_id = 0, | ||
| const void *stack_addr = NULL | ||
| ); | ||
|
|
||
| // Global counter on host. | ||
| // This variable is used if P2OPT_offload_do_data_persistence == 2. | ||
| // The variable used to identify offload constructs contained in one procedure. | ||
| // Call to OFFLOAD_CALL_COUNT() is inserted at HOST on entry of the routine. | ||
| extern "C" int OFFLOAD_CALL_COUNT(); | ||
|
|
||
| #endif // COMPILER_IF_HOST_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #include "compiler_if_target.h" | ||
|
|
||
| extern "C" void OFFLOAD_TARGET_ENTER( | ||
| OFFLOAD ofld, | ||
| int vars_total, | ||
| VarDesc *vars, | ||
| VarDesc2 *vars2 | ||
| ) | ||
| { | ||
| OFFLOAD_DEBUG_TRACE(3, "%s(%p, %d, %p, %p)\n", __func__, ofld, | ||
| vars_total, vars, vars2); | ||
| ofld->merge_var_descs(vars, vars2, vars_total); | ||
| ofld->scatter_copyin_data(); | ||
| } | ||
|
|
||
| extern "C" void OFFLOAD_TARGET_LEAVE( | ||
| OFFLOAD ofld | ||
| ) | ||
| { | ||
| OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ofld); | ||
| ofld->gather_copyout_data(); | ||
| } | ||
|
|
||
| extern "C" void OFFLOAD_TARGET_MAIN(void) | ||
| { | ||
| // initialize target part | ||
| __offload_target_init(); | ||
|
|
||
| // pass control to COI | ||
| PipelineStartExecutingRunFunctions(); | ||
| ProcessWaitForShutdown(); | ||
|
|
||
| OFFLOAD_DEBUG_TRACE(2, "Exiting main...\n"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| /*! \file | ||
| \brief The interface between compiler-generated target code and runtime library | ||
| */ | ||
|
|
||
| #ifndef COMPILER_IF_TARGET_H_INCLUDED | ||
| #define COMPILER_IF_TARGET_H_INCLUDED | ||
|
|
||
| #include "offload_target.h" | ||
|
|
||
| #define OFFLOAD_TARGET_ENTER OFFLOAD_PREFIX(target_enter) | ||
| #define OFFLOAD_TARGET_LEAVE OFFLOAD_PREFIX(target_leave) | ||
| #define OFFLOAD_TARGET_MAIN OFFLOAD_PREFIX(target_main) | ||
|
|
||
| /*! \fn OFFLOAD_TARGET_ENTER | ||
| \brief Fill in variable addresses using VarDesc array. | ||
| \brief Then call back the runtime library to fetch data. | ||
| \param ofld Offload descriptor created by runtime. | ||
| \param var_desc_num Number of variable descriptors. | ||
| \param var_desc Pointer to VarDesc array. | ||
| \param var_desc2 Pointer to VarDesc2 array. | ||
| */ | ||
| extern "C" void OFFLOAD_TARGET_ENTER( | ||
| OFFLOAD ofld, | ||
| int var_desc_num, | ||
| VarDesc *var_desc, | ||
| VarDesc2 *var_desc2 | ||
| ); | ||
|
|
||
| /*! \fn OFFLOAD_TARGET_LEAVE | ||
| \brief Call back the runtime library to gather outputs using VarDesc array. | ||
| \param ofld Offload descriptor created by OFFLOAD_TARGET_ACQUIRE. | ||
| */ | ||
| extern "C" void OFFLOAD_TARGET_LEAVE( | ||
| OFFLOAD ofld | ||
| ); | ||
|
|
||
| // Entry point for the target application. | ||
| extern "C" void OFFLOAD_TARGET_MAIN(void); | ||
|
|
||
| #endif // COMPILER_IF_TARGET_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #include "offload_common.h" | ||
|
|
||
| bool __dv_is_contiguous(const ArrDesc *dvp) | ||
| { | ||
| if (dvp->Flags & ArrDescFlagsContiguous) { | ||
| return true; | ||
| } | ||
|
|
||
| if (dvp->Rank != 0) { | ||
| if (dvp->Dim[0].Mult != dvp->Len) { | ||
| return false; | ||
| } | ||
| for (int i = 1; i < dvp->Rank; i++) { | ||
| if (dvp->Dim[i].Mult != | ||
| dvp->Dim[i-1].Extent * dvp->Dim[i-1].Mult) { | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| bool __dv_is_allocated(const ArrDesc *dvp) | ||
| { | ||
| return (dvp->Flags & ArrDescFlagsDefined); | ||
| } | ||
|
|
||
| uint64_t __dv_data_length(const ArrDesc *dvp) | ||
| { | ||
| uint64_t size; | ||
|
|
||
| if (dvp->Rank == 0) { | ||
| size = dvp->Len; | ||
| return size; | ||
| } | ||
|
|
||
| size = dvp->Len; | ||
| for (int i = 0; i < dvp->Rank; ++i) { | ||
| size += (dvp->Dim[i].Extent-1) * dvp->Dim[i].Mult; | ||
| } | ||
| return size; | ||
| } | ||
|
|
||
| uint64_t __dv_data_length(const ArrDesc *dvp, int64_t count) | ||
| { | ||
| if (dvp->Rank == 0) { | ||
| return count; | ||
| } | ||
|
|
||
| return count * dvp->Dim[0].Mult; | ||
| } | ||
|
|
||
| // Create CeanReadRanges data for reading contiguous ranges of | ||
| // noncontiguous array defined by the argument | ||
| CeanReadRanges * init_read_ranges_dv(const ArrDesc *dvp) | ||
| { | ||
| int64_t len; | ||
| int count; | ||
| int rank = dvp->Rank; | ||
| CeanReadRanges *res = NULL; | ||
|
|
||
| if (rank != 0) { | ||
| int i = 0; | ||
| len = dvp->Len; | ||
| if (dvp->Dim[0].Mult == len) { | ||
| for (i = 1; i < rank; i++) { | ||
| len *= dvp->Dim[i-1].Extent; | ||
| if (dvp->Dim[i].Mult != len) { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| res = (CeanReadRanges *)malloc( | ||
| sizeof(CeanReadRanges) + (rank - i) * sizeof(CeanReadDim)); | ||
| res -> last_noncont_ind = rank - i - 1; | ||
| count = 1; | ||
| for (; i < rank; i++) { | ||
| res->Dim[rank - i - 1].count = count; | ||
| res->Dim[rank - i - 1].size = dvp->Dim[i].Mult; | ||
| count *= dvp->Dim[i].Extent; | ||
| } | ||
| res -> range_max_number = count; | ||
| res -> range_size = len; | ||
| res -> ptr = (void*)dvp->Base; | ||
| res -> current_number = 0; | ||
| res -> init_offset = 0; | ||
| } | ||
| return res; | ||
| } | ||
|
|
||
| #if OFFLOAD_DEBUG > 0 | ||
| void __dv_desc_dump(const char *name, const ArrDesc *dvp) | ||
| { | ||
| OFFLOAD_TRACE(3, "%s DV %p\n", name, dvp); | ||
|
|
||
| if (dvp != 0) { | ||
| OFFLOAD_TRACE(3, | ||
| " dv->Base = 0x%lx\n" | ||
| " dv->Len = 0x%lx\n" | ||
| " dv->Offset = 0x%lx\n" | ||
| " dv->Flags = 0x%lx\n" | ||
| " dv->Rank = 0x%lx\n" | ||
| " dv->Resrvd = 0x%lx\n", | ||
| dvp->Base, | ||
| dvp->Len, | ||
| dvp->Offset, | ||
| dvp->Flags, | ||
| dvp->Rank, | ||
| dvp->Reserved); | ||
|
|
||
| for (int i = 0 ; i < dvp->Rank; i++) { | ||
| OFFLOAD_TRACE(3, | ||
| " (%d) Extent=%ld, Multiplier=%ld, LowerBound=%ld\n", | ||
| i, | ||
| dvp->Dim[i].Extent, | ||
| dvp->Dim[i].Mult, | ||
| dvp->Dim[i].LowerBound); | ||
| } | ||
| } | ||
| } | ||
| #endif // OFFLOAD_DEBUG > 0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #ifndef DV_UTIL_H_INCLUDED | ||
| #define DV_UTIL_H_INCLUDED | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| // Dope vector declarations | ||
| #define ArrDescMaxArrayRank 31 | ||
|
|
||
| // Dope vector flags | ||
| #define ArrDescFlagsDefined 1 | ||
| #define ArrDescFlagsNodealloc 2 | ||
| #define ArrDescFlagsContiguous 4 | ||
|
|
||
| typedef int64_t dv_size; | ||
|
|
||
| typedef struct DimDesc { | ||
| dv_size Extent; // Number of elements in this dimension | ||
| dv_size Mult; // Multiplier for this dimension. | ||
| // The number of bytes between successive | ||
| // elements in this dimension. | ||
| dv_size LowerBound; // LowerBound of this dimension | ||
| } DimDesc ; | ||
|
|
||
| typedef struct ArrDesc { | ||
| dv_size Base; // Base address | ||
| dv_size Len; // Length of data type, used only for | ||
| // character strings. | ||
| dv_size Offset; | ||
| dv_size Flags; // Flags | ||
| dv_size Rank; // Rank of pointer | ||
| dv_size Reserved; // reserved for openmp requests | ||
| DimDesc Dim[ArrDescMaxArrayRank]; | ||
| } ArrDesc ; | ||
|
|
||
| typedef ArrDesc* pArrDesc; | ||
|
|
||
| bool __dv_is_contiguous(const ArrDesc *dvp); | ||
|
|
||
| bool __dv_is_allocated(const ArrDesc *dvp); | ||
|
|
||
| uint64_t __dv_data_length(const ArrDesc *dvp); | ||
|
|
||
| uint64_t __dv_data_length(const ArrDesc *dvp, int64_t nelems); | ||
|
|
||
| CeanReadRanges * init_read_ranges_dv(const ArrDesc *dvp); | ||
|
|
||
| #if OFFLOAD_DEBUG > 0 | ||
| void __dv_desc_dump(const char *name, const ArrDesc *dvp); | ||
| #else // OFFLOAD_DEBUG | ||
| #define __dv_desc_dump(name, dvp) | ||
| #endif // OFFLOAD_DEBUG | ||
|
|
||
| #endif // DV_UTIL_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,276 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #if !defined(LIBOFFLOAD_ERROR_CODES_H) | ||
| #define LIBOFFLOAD_ERROR_CODES_H | ||
| #include <stdarg.h> | ||
| #include <stdlib.h> | ||
| #include <stdio.h> | ||
|
|
||
| typedef enum | ||
| { | ||
| c_device_is_not_available = 0, | ||
| c_invalid_device_number, | ||
| c_offload1, | ||
| c_unknown_var_type, | ||
| c_send_func_ptr, | ||
| c_receive_func_ptr, | ||
| c_offload_malloc, | ||
| c_invalid_env_var_value, | ||
| c_invalid_env_var_int_value, | ||
| c_invalid_env_report_value, | ||
| c_offload_signaled1, | ||
| c_offload_signaled2, | ||
| c_myotarget_checkresult, | ||
| c_myowrapper_checkresult, | ||
| c_offload_descriptor_offload, | ||
| c_merge_var_descs1, | ||
| c_merge_var_descs2, | ||
| c_mic_parse_env_var_list1, | ||
| c_mic_parse_env_var_list2, | ||
| c_mic_process_exit_ret, | ||
| c_mic_process_exit_sig, | ||
| c_mic_process_exit, | ||
| c_mic_init3, | ||
| c_mic_init4, | ||
| c_mic_init5, | ||
| c_mic_init6, | ||
| c_no_static_var_data, | ||
| c_no_ptr_data, | ||
| c_get_engine_handle, | ||
| c_get_engine_index, | ||
| c_process_create, | ||
| c_process_get_func_handles, | ||
| c_process_wait_shutdown, | ||
| c_process_proxy_flush, | ||
| c_load_library, | ||
| c_pipeline_create, | ||
| c_pipeline_run_func, | ||
| c_pipeline_start_run_funcs, | ||
| c_buf_create, | ||
| c_buf_create_out_of_mem, | ||
| c_buf_create_from_mem, | ||
| c_buf_destroy, | ||
| c_buf_map, | ||
| c_buf_unmap, | ||
| c_buf_read, | ||
| c_buf_write, | ||
| c_buf_copy, | ||
| c_buf_get_address, | ||
| c_buf_add_ref, | ||
| c_buf_release_ref, | ||
| c_buf_set_state, | ||
| c_event_wait, | ||
| c_zero_or_neg_ptr_len, | ||
| c_zero_or_neg_transfer_size, | ||
| c_bad_ptr_mem_range, | ||
| c_different_src_and_dstn_sizes, | ||
| c_ranges_dont_match, | ||
| c_destination_is_over, | ||
| c_slice_of_noncont_array, | ||
| c_non_contiguous_dope_vector, | ||
| c_pointer_array_mismatch, | ||
| c_omp_invalid_device_num_env, | ||
| c_omp_invalid_device_num, | ||
| c_unknown_binary_type, | ||
| c_multiple_target_exes, | ||
| c_no_target_exe, | ||
| c_report_host, | ||
| c_report_target, | ||
| c_report_title, | ||
| c_report_from_file, | ||
| c_report_file, | ||
| c_report_line, | ||
| c_report_tag, | ||
| c_report_seconds, | ||
| c_report_bytes, | ||
| c_report_mic, | ||
| c_report_cpu_time, | ||
| c_report_cpu_to_mic_data, | ||
| c_report_mic_time, | ||
| c_report_mic_to_cpu_data, | ||
| c_report_unknown_timer_node, | ||
| c_report_unknown_trace_node, | ||
| c_report_offload, | ||
| c_report_w_tag, | ||
| c_report_state, | ||
| c_report_start, | ||
| c_report_init, | ||
| c_report_logical_card, | ||
| c_report_physical_card, | ||
| c_report_register, | ||
| c_report_init_func, | ||
| c_report_create_buf_host, | ||
| c_report_create_buf_mic, | ||
| c_report_send_pointer_data, | ||
| c_report_sent_pointer_data, | ||
| c_report_gather_copyin_data, | ||
| c_report_copyin_data, | ||
| c_report_state_signal, | ||
| c_report_signal, | ||
| c_report_wait, | ||
| c_report_compute, | ||
| c_report_receive_pointer_data, | ||
| c_report_received_pointer_data, | ||
| c_report_start_target_func, | ||
| c_report_var, | ||
| c_report_scatter_copyin_data, | ||
| c_report_gather_copyout_data, | ||
| c_report_scatter_copyout_data, | ||
| c_report_copyout_data, | ||
| c_report_unregister, | ||
| c_report_destroy, | ||
| c_report_myoinit, | ||
| c_report_myoregister, | ||
| c_report_myofini, | ||
| c_report_mic_myo_shared, | ||
| c_report_mic_myo_fptr, | ||
| c_report_myosharedmalloc, | ||
| c_report_myosharedfree, | ||
| c_report_myosharedalignedmalloc, | ||
| c_report_myosharedalignedfree, | ||
| c_report_myoacquire, | ||
| c_report_myorelease, | ||
| c_coipipe_max_number | ||
| } error_types; | ||
|
|
||
| enum OffloadHostPhase { | ||
| // Total time on host for entire offload | ||
| c_offload_host_total_offload = 0, | ||
|
|
||
| // Time to load target binary | ||
| c_offload_host_initialize, | ||
|
|
||
| // Time to acquire lrb availability dynamically | ||
| c_offload_host_target_acquire, | ||
|
|
||
| // Time to wait for dependencies | ||
| c_offload_host_wait_deps, | ||
|
|
||
| // Time to allocate pointer buffers, initiate writes for pointers | ||
| // and calculate size of copyin/copyout buffer | ||
| c_offload_host_setup_buffers, | ||
|
|
||
| // Time to allocate pointer buffers | ||
| c_offload_host_alloc_buffers, | ||
|
|
||
| // Time to initialize misc data | ||
| c_offload_host_setup_misc_data, | ||
|
|
||
| // Time to allocate copyin/copyout buffer | ||
| c_offload_host_alloc_data_buffer, | ||
|
|
||
| // Time to initiate writes from host pointers to buffers | ||
| c_offload_host_send_pointers, | ||
|
|
||
| // Time to Gather IN data of offload into buffer | ||
| c_offload_host_gather_inputs, | ||
|
|
||
| // Time to map buffer | ||
| c_offload_host_map_in_data_buffer, | ||
|
|
||
| // Time to unmap buffer | ||
| c_offload_host_unmap_in_data_buffer, | ||
|
|
||
| // Time to start remote function call that does computation on lrb | ||
| c_offload_host_start_compute, | ||
|
|
||
| // Time to wait for compute to finish | ||
| c_offload_host_wait_compute, | ||
|
|
||
| // Time to initiate reads from pointer buffers | ||
| c_offload_host_start_buffers_reads, | ||
|
|
||
| // Time to update host variabels with OUT data from buffer | ||
| c_offload_host_scatter_outputs, | ||
|
|
||
| // Time to map buffer | ||
| c_offload_host_map_out_data_buffer, | ||
|
|
||
| // Time to unmap buffer | ||
| c_offload_host_unmap_out_data_buffer, | ||
|
|
||
| // Time to wait reads from buffers to finish | ||
| c_offload_host_wait_buffers_reads, | ||
|
|
||
| // Time to destroy buffers that are no longer needed | ||
| c_offload_host_destroy_buffers, | ||
|
|
||
| // LAST TIME MONITOR | ||
| c_offload_host_max_phase | ||
| }; | ||
|
|
||
| enum OffloadTargetPhase { | ||
| // Total time spent on the target | ||
| c_offload_target_total_time = 0, | ||
|
|
||
| // Time to initialize offload descriptor | ||
| c_offload_target_descriptor_setup, | ||
|
|
||
| // Time to find target entry point in lookup table | ||
| c_offload_target_func_lookup, | ||
|
|
||
| // Total time spend executing offload entry | ||
| c_offload_target_func_time, | ||
|
|
||
| // Time to initialize target variables with IN values from buffer | ||
| c_offload_target_scatter_inputs, | ||
|
|
||
| // Time to add buffer reference for pointer buffers | ||
| c_offload_target_add_buffer_refs, | ||
|
|
||
| // Total time on lrb for computation | ||
| c_offload_target_compute, | ||
|
|
||
| // On lrb, time to copy OUT into buffer | ||
| c_offload_target_gather_outputs, | ||
|
|
||
| // Time to release buffer references | ||
| c_offload_target_release_buffer_refs, | ||
|
|
||
| // LAST TIME MONITOR | ||
| c_offload_target_max_phase | ||
| }; | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
| void __liboffload_error_support(error_types input_tag, ...); | ||
| void __liboffload_report_support(error_types input_tag, ...); | ||
| char const *offload_get_message_str(int msgCode); | ||
| char const * report_get_message_str(error_types input_tag); | ||
| char const * report_get_host_stage_str(int i); | ||
| char const * report_get_target_stage_str(int i); | ||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #define test_msg_cat(nm, msg) \ | ||
| fprintf(stderr, "\t TEST for %s \n \t", nm); \ | ||
| __liboffload_error_support(msg); | ||
|
|
||
| #define test_msg_cat1(nm, msg, ...) \ | ||
| fprintf(stderr, "\t TEST for %s \n \t", nm); \ | ||
| __liboffload_error_support(msg, __VA_ARGS__); | ||
|
|
||
| void write_message(FILE * file, int msgCode, va_list args_p); | ||
|
|
||
| #define LIBOFFLOAD_ERROR __liboffload_error_support | ||
|
|
||
| #ifdef TARGET_WINNT | ||
| #define LIBOFFLOAD_ABORT \ | ||
| _set_abort_behavior(0, _WRITE_ABORT_MSG); \ | ||
| abort() | ||
| #else | ||
| #define LIBOFFLOAD_ABORT \ | ||
| abort() | ||
| #endif | ||
|
|
||
| #endif // !defined(LIBOFFLOAD_ERROR_CODES_H) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
|
|
||
| #include <stdio.h> | ||
|
|
||
| // =========================================================================== | ||
| // Bring in the static string table and the enumerations for indexing into | ||
| // it. | ||
| // =========================================================================== | ||
|
|
||
| #include "liboffload_msg.h" | ||
|
|
||
| # define DYNART_STDERR_PUTS(__message_text__) fputs((__message_text__),stderr) | ||
|
|
||
| // =========================================================================== | ||
| // Now the code for accessing the message catalogs | ||
| // =========================================================================== | ||
|
|
||
|
|
||
| void write_message(FILE * file, int msgCode) { | ||
| fputs(MESSAGE_TABLE_NAME[ msgCode ], file); | ||
| fflush(file); | ||
| } | ||
|
|
||
| char const *offload_get_message_str(int msgCode) { | ||
| return MESSAGE_TABLE_NAME[ msgCode ]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #if defined(LINUX) || defined(FREEBSD) | ||
| #include <mm_malloc.h> | ||
| #endif | ||
|
|
||
| #include "offload_common.h" | ||
|
|
||
| // The debug routines | ||
|
|
||
| #if OFFLOAD_DEBUG > 0 | ||
|
|
||
| void __dump_bytes( | ||
| int trace_level, | ||
| const void *data, | ||
| int len | ||
| ) | ||
| { | ||
| if (console_enabled > trace_level) { | ||
| const uint8_t *arr = (const uint8_t*) data; | ||
| char buffer[4096]; | ||
| char *bufferp; | ||
| int count = 0; | ||
|
|
||
| bufferp = buffer; | ||
| while (len--) { | ||
| sprintf(bufferp, "%02x", *arr++); | ||
| bufferp += 2; | ||
| count++; | ||
| if ((count&3) == 0) { | ||
| sprintf(bufferp, " "); | ||
| bufferp++; | ||
| } | ||
| if ((count&63) == 0) { | ||
| OFFLOAD_DEBUG_TRACE(trace_level, "%s\n", buffer); | ||
| bufferp = buffer; | ||
| count = 0; | ||
| } | ||
| } | ||
| if (count) { | ||
| OFFLOAD_DEBUG_TRACE(trace_level, "%s\n", buffer); | ||
| } | ||
| } | ||
| } | ||
| #endif // OFFLOAD_DEBUG | ||
|
|
||
| // The Marshaller and associated routines | ||
|
|
||
| void Marshaller::send_data( | ||
| const void *data, | ||
| int64_t length | ||
| ) | ||
| { | ||
| OFFLOAD_DEBUG_TRACE(2, "send_data(%p, %lld)\n", | ||
| data, length); | ||
| memcpy(buffer_ptr, data, (size_t)length); | ||
| buffer_ptr += length; | ||
| tfr_size += length; | ||
| } | ||
|
|
||
| void Marshaller::receive_data( | ||
| void *data, | ||
| int64_t length | ||
| ) | ||
| { | ||
| OFFLOAD_DEBUG_TRACE(2, "receive_data(%p, %lld)\n", | ||
| data, length); | ||
| memcpy(data, buffer_ptr, (size_t)length); | ||
| buffer_ptr += length; | ||
| tfr_size += length; | ||
| } | ||
|
|
||
| // Send function pointer | ||
| void Marshaller::send_func_ptr( | ||
| const void* data | ||
| ) | ||
| { | ||
| const char* name; | ||
| size_t length; | ||
|
|
||
| if (data != 0) { | ||
| name = __offload_funcs.find_name(data); | ||
| if (name == 0) { | ||
| #if OFFLOAD_DEBUG > 0 | ||
| if (console_enabled > 2) { | ||
| __offload_funcs.dump(); | ||
| } | ||
| #endif // OFFLOAD_DEBUG > 0 | ||
|
|
||
| LIBOFFLOAD_ERROR(c_send_func_ptr, data); | ||
| exit(1); | ||
| } | ||
| length = strlen(name) + 1; | ||
| } | ||
| else { | ||
| name = ""; | ||
| length = 1; | ||
| } | ||
|
|
||
| memcpy(buffer_ptr, name, length); | ||
| buffer_ptr += length; | ||
| tfr_size += length; | ||
| } | ||
|
|
||
| // Receive function pointer | ||
| void Marshaller::receive_func_ptr( | ||
| const void** data | ||
| ) | ||
| { | ||
| const char* name; | ||
| size_t length; | ||
|
|
||
| name = (const char*) buffer_ptr; | ||
| if (name[0] != '\0') { | ||
| *data = __offload_funcs.find_addr(name); | ||
| if (*data == 0) { | ||
| #if OFFLOAD_DEBUG > 0 | ||
| if (console_enabled > 2) { | ||
| __offload_funcs.dump(); | ||
| } | ||
| #endif // OFFLOAD_DEBUG > 0 | ||
|
|
||
| LIBOFFLOAD_ERROR(c_receive_func_ptr, name); | ||
| exit(1); | ||
| } | ||
| length = strlen(name) + 1; | ||
| } | ||
| else { | ||
| *data = 0; | ||
| length = 1; | ||
| } | ||
|
|
||
| buffer_ptr += length; | ||
| tfr_size += length; | ||
| } | ||
|
|
||
| // End of the Marshaller and associated routines | ||
|
|
||
| extern void *OFFLOAD_MALLOC( | ||
| size_t size, | ||
| size_t align | ||
| ) | ||
| { | ||
| void *ptr; | ||
| int err; | ||
|
|
||
| OFFLOAD_DEBUG_TRACE(2, "%s(%lld, %lld)\n", __func__, size, align); | ||
|
|
||
| if (align < sizeof(void*)) { | ||
| align = sizeof(void*); | ||
| } | ||
|
|
||
| ptr = _mm_malloc(size, align); | ||
| if (ptr == NULL) { | ||
| LIBOFFLOAD_ERROR(c_offload_malloc, size, align); | ||
| exit(1); | ||
| } | ||
|
|
||
| OFFLOAD_DEBUG_TRACE(2, "%s returned %p\n", __func__, ptr); | ||
|
|
||
| return ptr; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,354 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #include "offload_env.h" | ||
| #include <string.h> | ||
| #include <ctype.h> | ||
| #include "offload_util.h" | ||
| #include "liboffload_error_codes.h" | ||
|
|
||
| // for environment variables valid on all cards | ||
| const int MicEnvVar::any_card = -1; | ||
|
|
||
| MicEnvVar::~MicEnvVar() | ||
| { | ||
| for (std::list<MicEnvVar::CardEnvVars*>::const_iterator | ||
| it = card_spec_list.begin(); | ||
| it != card_spec_list.end(); it++) { | ||
| CardEnvVars *card_data = *it; | ||
| delete card_data; | ||
| } | ||
| } | ||
|
|
||
| MicEnvVar::VarValue::~VarValue() | ||
| { | ||
| free(env_var_value); | ||
| } | ||
|
|
||
| MicEnvVar::CardEnvVars::~CardEnvVars() | ||
| { | ||
| for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin(); | ||
| it != env_vars.end(); it++) { | ||
| VarValue *var_value = *it; | ||
| delete var_value; | ||
| } | ||
| } | ||
|
|
||
| // Searching for card in "card_spec_list" list with the same "number" | ||
|
|
||
| MicEnvVar::CardEnvVars* MicEnvVar::get_card(int number) | ||
| { | ||
| if (number == any_card) { | ||
| return &common_vars; | ||
| } | ||
| for (std::list<MicEnvVar::CardEnvVars*>::const_iterator | ||
| it = card_spec_list.begin(); | ||
| it != card_spec_list.end(); it++) { | ||
| CardEnvVars *card_data = *it; | ||
| if (card_data->card_number == number) { | ||
| return card_data; | ||
| } | ||
| } | ||
| return NULL; | ||
| } | ||
|
|
||
| // Searching for environment variable in "env_var" list with the same name | ||
|
|
||
| MicEnvVar::VarValue* MicEnvVar::CardEnvVars::find_var( | ||
| char* env_var_name, | ||
| int env_var_name_length | ||
| ) | ||
| { | ||
| for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin(); | ||
| it != env_vars.end(); it++) { | ||
| VarValue *var_value = *it; | ||
| if (var_value->length == env_var_name_length && | ||
| !strncmp(var_value->env_var, env_var_name, | ||
| env_var_name_length)) { | ||
| return var_value; | ||
| } | ||
| } | ||
| return NULL; | ||
| } | ||
|
|
||
| void MicEnvVar::analyze_env_var(char *env_var_string) | ||
| { | ||
| char *env_var_name; | ||
| char *env_var_def; | ||
| int card_number; | ||
| int env_var_name_length; | ||
| MicEnvVarKind env_var_kind; | ||
|
|
||
| env_var_kind = get_env_var_kind(env_var_string, | ||
| &card_number, | ||
| &env_var_name, | ||
| &env_var_name_length, | ||
| &env_var_def); | ||
| switch (env_var_kind) { | ||
| case c_mic_var: | ||
| case c_mic_card_var: | ||
| add_env_var(card_number, | ||
| env_var_name, | ||
| env_var_name_length, | ||
| env_var_def); | ||
| break; | ||
| case c_mic_card_env: | ||
| mic_parse_env_var_list(card_number, env_var_def); | ||
| break; | ||
| case c_no_mic: | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| void MicEnvVar::add_env_var( | ||
| int card_number, | ||
| char *env_var_name, | ||
| int env_var_name_length, | ||
| char *env_var_def | ||
| ) | ||
| { | ||
| VarValue *var; | ||
| CardEnvVars *card; | ||
|
|
||
| // The case corresponds to common env var definition of kind | ||
| // <mic-prefix>_<var> | ||
| if (card_number == any_card) { | ||
| card = &common_vars; | ||
| } | ||
| else { | ||
| card = get_card(card_number); | ||
| if (!card) { | ||
| // definition for new card occured | ||
| card = new CardEnvVars(card_number); | ||
| card_spec_list.push_back(card); | ||
| } | ||
|
|
||
| } | ||
| var = card->find_var(env_var_name, env_var_name_length); | ||
| if (!var) { | ||
| // put new env var definition in "env_var" list | ||
| var = new VarValue(env_var_name, env_var_name_length, env_var_def); | ||
| card->env_vars.push_back(var); | ||
| } | ||
| } | ||
|
|
||
| // The routine analyses string pointed by "env_var_string" argument | ||
| // according to the following syntax: | ||
| // | ||
| // Specification of prefix for MIC environment variables | ||
| // MIC_ENV_PREFIX=<mic-prefix> | ||
| // | ||
| // Setting single MIC environment variable | ||
| // <mic-prefix>_<var>=<value> | ||
| // <mic-prefix>_<card-number>_<var>=<value> | ||
|
|
||
| // Setting multiple MIC environment variables | ||
| // <mic-prefix>_<card-number>_ENV=<env-vars> | ||
|
|
||
| MicEnvVarKind MicEnvVar::get_env_var_kind( | ||
| char *env_var_string, | ||
| int *card_number, | ||
| char **env_var_name, | ||
| int *env_var_name_length, | ||
| char **env_var_def | ||
| ) | ||
| { | ||
| int len = strlen(prefix); | ||
| char *c = env_var_string; | ||
| int num = 0; | ||
| bool card_is_set = false; | ||
|
|
||
| if (strncmp(c, prefix, len) != 0 || c[len] != '_') { | ||
| return c_no_mic; | ||
| } | ||
| c += len + 1; | ||
|
|
||
| *card_number = any_card; | ||
| if (isdigit(*c)) { | ||
| while (isdigit (*c)) { | ||
| num = (*c++ - '0') + (num * 10); | ||
| } | ||
| if (*c != '_') { | ||
| return c_no_mic; | ||
| } | ||
| c++; | ||
| *card_number = num; | ||
| card_is_set = true; | ||
| } | ||
| if (!isalpha(*c)) { | ||
| return c_no_mic; | ||
| } | ||
| *env_var_name = *env_var_def = c; | ||
| if (strncmp(c, "ENV=", 4) == 0) { | ||
| if (!card_is_set) { | ||
| *env_var_name_length = 3; | ||
| *env_var_name = *env_var_def = c; | ||
| *env_var_def = strdup(*env_var_def); | ||
| return c_mic_var; | ||
| } | ||
| *env_var_def = c + strlen("ENV="); | ||
| *env_var_def = strdup(*env_var_def); | ||
| return c_mic_card_env; | ||
| } | ||
| if (isalpha(*c)) { | ||
| *env_var_name_length = 0; | ||
| while (isalnum(*c) || *c == '_') { | ||
| c++; | ||
| (*env_var_name_length)++; | ||
| } | ||
| } | ||
| if (*c != '=') { | ||
| return c_no_mic; | ||
| } | ||
| *env_var_def = strdup(*env_var_def); | ||
| return card_is_set? c_mic_card_var : c_mic_var; | ||
| } | ||
|
|
||
| // analysing <env-vars> in form: | ||
| // <mic-prefix>_<card-number>_ENV=<env-vars> | ||
| // where: | ||
| // | ||
| // <env-vars>: | ||
| // <env-var> | ||
| // <env-vars> | <env-var> | ||
| // | ||
| // <env-var>: | ||
| // variable=value | ||
| // variable="value" | ||
| // variable= | ||
|
|
||
| void MicEnvVar::mic_parse_env_var_list( | ||
| int card_number, char *env_vars_def_list) | ||
| { | ||
| char *c = env_vars_def_list; | ||
| char *env_var_name; | ||
| int env_var_name_length; | ||
| char *env_var_def; | ||
| bool var_is_quoted; | ||
|
|
||
| if (*c == '"') { | ||
| c++; | ||
| } | ||
| while (*c != 0) { | ||
| var_is_quoted = false; | ||
| env_var_name = c; | ||
| env_var_name_length = 0; | ||
| if (isalpha(*c)) { | ||
| while (isalnum(*c) || *c == '_') { | ||
| c++; | ||
| env_var_name_length++; | ||
| } | ||
| } | ||
| else { | ||
| LIBOFFLOAD_ERROR(c_mic_parse_env_var_list1); | ||
| return; | ||
| } | ||
| if (*c != '=') { | ||
| LIBOFFLOAD_ERROR(c_mic_parse_env_var_list2); | ||
| return; | ||
| } | ||
| c++; | ||
|
|
||
| if (*c == '"') { | ||
| var_is_quoted = true; | ||
| c++; | ||
| } | ||
| // Environment variable values that contain | will need to be escaped. | ||
| while (*c != 0 && *c != '|' && | ||
| (!var_is_quoted || *c != '"')) | ||
| { | ||
| // skip escaped symbol | ||
| if (*c == '\\') { | ||
| c++; | ||
| } | ||
| c++; | ||
| } | ||
| if (var_is_quoted) { | ||
| c++; // for " | ||
| while (*c != 0 && *c != '|') { | ||
| c++; | ||
| } | ||
| } | ||
|
|
||
| int sz = c - env_var_name; | ||
| env_var_def = (char*)malloc(sz); | ||
| memcpy(env_var_def, env_var_name, sz); | ||
| env_var_def[sz] = 0; | ||
|
|
||
| if (*c == '|') { | ||
| c++; | ||
| while (*c != 0 && *c == ' ') { | ||
| c++; | ||
| } | ||
| } | ||
| add_env_var(card_number, | ||
| env_var_name, | ||
| env_var_name_length, | ||
| env_var_def); | ||
| } | ||
| } | ||
|
|
||
| // Collect all definitions for the card with number "card_num". | ||
| // The returned result is vector of string pointers defining one | ||
| // environment variable. The vector is terminated by NULL pointer. | ||
| // In the begining of the vector there are env vars defined as | ||
| // <mic-prefix>_<card-number>_<var>=<value> | ||
| // or | ||
| // <mic-prefix>_<card-number>_ENV=<env-vars> | ||
| // where <card-number> is equal to "card_num" | ||
| // They are followed by definitions valid for any card | ||
| // and absent in previous definitions. | ||
|
|
||
| char** MicEnvVar::create_environ_for_card(int card_num) | ||
| { | ||
| VarValue *var_value; | ||
| VarValue *var_value_find; | ||
| CardEnvVars *card_data = get_card(card_num); | ||
| CardEnvVars *card_data_common; | ||
| std::list<char*> new_env; | ||
| char **rez; | ||
|
|
||
| if (!prefix) { | ||
| return NULL; | ||
| } | ||
| // There is no personel env var definitions for the card with | ||
| // number "card_num" | ||
| if (!card_data) { | ||
| return create_environ_for_card(any_card); | ||
| } | ||
|
|
||
| for (std::list<MicEnvVar::VarValue*>::const_iterator | ||
| it = card_data->env_vars.begin(); | ||
| it != card_data->env_vars.end(); it++) { | ||
| var_value = *it; | ||
| new_env.push_back(var_value->env_var_value); | ||
| } | ||
|
|
||
| if (card_num != any_card) { | ||
| card_data_common = get_card(any_card); | ||
| for (std::list<MicEnvVar::VarValue*>::const_iterator | ||
| it = card_data_common->env_vars.begin(); | ||
| it != card_data_common->env_vars.end(); it++) { | ||
| var_value = *it; | ||
| var_value_find = card_data->find_var(var_value->env_var, | ||
| var_value->length); | ||
| if (!var_value_find) { | ||
| new_env.push_back(var_value->env_var_value); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| int new_env_size = new_env.size(); | ||
| rez = (char**) malloc((new_env_size + 1) * sizeof(char*)); | ||
| std::copy(new_env.begin(), new_env.end(), rez); | ||
| rez[new_env_size] = 0; | ||
| return rez; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is dual licensed under the MIT and the University of Illinois Open | ||
| // Source Licenses. See LICENSE.txt for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
|
|
||
| #ifndef OFFLOAD_ENV_H_INCLUDED | ||
| #define OFFLOAD_ENV_H_INCLUDED | ||
|
|
||
| #include <list> | ||
|
|
||
| // data structure and routines to parse MIC user environment and pass to MIC | ||
|
|
||
| enum MicEnvVarKind | ||
| { | ||
| c_no_mic, // not MIC env var | ||
| c_mic_var, // for <mic-prefix>_<var> | ||
| c_mic_card_var, // for <mic-prefix>_<card-number>_<var> | ||
| c_mic_card_env // for <mic-prefix>_<card-number>_ENV | ||
| }; | ||
|
|
||
| struct MicEnvVar { | ||
| public: | ||
| MicEnvVar() : prefix(0) {} | ||
| ~MicEnvVar(); | ||
|
|
||
| void analyze_env_var(char *env_var_string); | ||
| char** create_environ_for_card(int card_num); | ||
| MicEnvVarKind get_env_var_kind( | ||
| char *env_var_string, | ||
| int *card_number, | ||
| char **env_var_name, | ||
| int *env_var_name_length, | ||
| char **env_var_def | ||
| ); | ||
| void add_env_var( | ||
| int card_number, | ||
| char *env_var_name, | ||
| int env_var_name_length, | ||
| char *env_var_def | ||
| ); | ||
|
|
||
| void set_prefix(const char *pref) { | ||
| prefix = (pref && *pref != '\0') ? pref : 0; | ||
| } | ||
|
|
||
| struct VarValue { | ||
| public: | ||
| char* env_var; | ||
| int length; | ||
| char* env_var_value; | ||
|
|
||
| VarValue(char* var, int ln, char* value) | ||
| { | ||
| env_var = var; | ||
| length = ln; | ||
| env_var_value = value; | ||
| } | ||
| ~VarValue(); | ||
| }; | ||
|
|
||
| struct CardEnvVars { | ||
| public: | ||
|
|
||
| int card_number; | ||
| std::list<struct VarValue*> env_vars; | ||
|
|
||
| CardEnvVars() { card_number = any_card; } | ||
| CardEnvVars(int num) { card_number = num; } | ||
| ~CardEnvVars(); | ||
|
|
||
| void add_new_env_var(int number, char *env_var, int length, | ||
| char *env_var_value); | ||
| VarValue* find_var(char* env_var_name, int env_var_name_length); | ||
| }; | ||
| static const int any_card; | ||
|
|
||
| private: | ||
| void mic_parse_env_var_list(int card_number, char *env_var_def); | ||
| CardEnvVars* get_card(int number); | ||
|
|
||
| const char *prefix; | ||
| std::list<struct CardEnvVars *> card_spec_list; | ||
| CardEnvVars common_vars; | ||
| }; | ||
|
|
||
| #endif // OFFLOAD_ENV_H_INCLUDED |