Skip to content
This repository has been archived by the owner on Feb 2, 2024. It is now read-only.

VTune integration #814

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions examples/vtune_integration/basic_usage_vtune_profiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import pandas as pd
from numba import njit
import sdc
import vtune as vt
from vtune import task_begin, task_end, domain, string_handle_create
import ctypes
import itt

handle = string_handle_create("Function")


@njit
def dataframe_head(df):
task_begin(domain, handle)
series = df['A'].head(n=4)
task_end(domain)
return series


df = pd.DataFrame({'A': [1, 2, 4, 6, 4, 2], 'B': [3., 2., 77., 2., 5., 6.5]})

print(dataframe_head(df))
2 changes: 2 additions & 0 deletions sdc/datatypes/hpat_pandas_series_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
from sdc.functions import numpy_like
from sdc.hiframes.api import isna
from sdc.datatypes.hpat_pandas_groupby_functions import init_series_groupby
from vtune import vtune_profiling_overload

from .pandas_series_functions import apply
from .pandas_series_functions import map as _map
Expand Down Expand Up @@ -2268,6 +2269,7 @@ def hpat_pandas_series_corr_impl(self, other, method='pearson', min_periods=None


@sdc_overload_method(SeriesType, 'head')
@vtune_profiling_overload(name_handle="Series_head")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be part of sdc_overload_method decorator. We can extract type name and method name from where.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You actually could call this decorator inside sdc_overload_method

def hpat_pandas_series_head(self, n=5):
"""
Intel Scalable Dataframe Compiler User Guide
Expand Down
5 changes: 5 additions & 0 deletions sdc/hiframes/boxing.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
box_categorical_array, unbox_categorical_array)
from sdc.hiframes.pd_series_ext import SeriesType
from sdc.hiframes.pd_series_type import _get_series_array_type
from vtune import vtune_profiling_boxing

from .. import hstr_ext
import llvmlite.binding as ll
Expand Down Expand Up @@ -74,6 +75,7 @@ def typeof_pd_str_series(val, c):


@unbox(DataFrameType)
@vtune_profiling_boxing(name_handle="Dataframe_unbox")
def unbox_dataframe(typ, val, c):
"""unbox dataframe to an empty DataFrame struct
columns will be extracted later if necessary.
Expand Down Expand Up @@ -196,6 +198,7 @@ def _infer_index_type(index):


@box(DataFrameType)
@vtune_profiling_boxing(name_handle="Dataframe_box")
def box_dataframe(typ, val, c):
context = c.context
builder = c.builder
Expand Down Expand Up @@ -286,6 +289,7 @@ def codegen(context, builder, sig, args):


@unbox(SeriesType)
@vtune_profiling_boxing(name_handle="Series_unbox")
def unbox_series(typ, val, c):
arr_obj = c.pyapi.object_getattr_string(val, "values")
series = cgutils.create_struct_proxy(typ)(c.context, c.builder)
Expand Down Expand Up @@ -322,6 +326,7 @@ def _unbox_series_data(dtype, data_typ, arr_obj, c):


@box(SeriesType)
@vtune_profiling_boxing(name_handle="Series_box")
def box_series(typ, val, c):
"""
"""
Expand Down
97 changes: 97 additions & 0 deletions vtune.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import ctypes
import itt
import llvmlite.binding as ll
from llvmlite.llvmpy.core import Type as LLType
from llvmlite import ir as lir
from llvmlite.llvmpy.core import Constant
from inspect import signature
import numba

functype_domain = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p)
ctypes_domain = functype_domain(itt.__itt_domain_create)
domain = ctypes_domain(b"VTune.Profiling.SDC\0")

functype_string_handle_create = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p)
ctypes_string_handle_create = functype_string_handle_create(itt.__itt_string_handle_create)

functype_task_begin = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p)
task_begin = functype_task_begin(itt.__itt_task_begin)

functype_task_end = ctypes.CFUNCTYPE(None, ctypes.c_void_p)
task_end = functype_task_end(itt.__itt_task_end)

ll.add_symbol('__itt_task_begin_new', itt.__itt_task_begin)
ll.add_symbol('__itt_task_end_new', itt.__itt_task_end)


def string_handle_create(string):
return ctypes_string_handle_create(string.encode())


def vtune_profiling_boxing(name_handle):
def task(func):
handle = string_handle_create(name_handle)

def wrapper(typ, val, c):
fnty = LLType.function(LLType.void(), [c.pyapi.voidptr, c.pyapi.voidptr])
fn = c.pyapi._get_function(fnty, name="__itt_task_begin_new")
domain_const = lir.Constant(LLType.int(64), domain)
handle_const = lir.Constant(LLType.int(64), handle)
c.builder.call(fn, [Constant.inttoptr(domain_const, c.pyapi.voidptr),
Constant.inttoptr(handle_const, c.pyapi.voidptr)])

return_value = func(typ, val, c)

fnty_end = LLType.function(LLType.void(), [c.pyapi.voidptr])
fn_end = c.pyapi._get_function(fnty_end, name="__itt_task_end_new")
c.builder.call(fn_end, [Constant.inttoptr(domain_const, c.pyapi.voidptr)])

return return_value

return wrapper

return task


def vtune_profiling_overload(name_handle):
def task(func):
handle = string_handle_create(name_handle)
args = signature(func)
return exec_impl(func, handle)

return task


def codegen_exec_impl(func, handle):
sig = signature(func)
sig_str = str(sig)
args_str = ', '.join(sig.parameters.keys())
func_lines = [f"def wrapper{sig_str}:",
f" overload_result = func({args_str})",
f" result = numba.njit(overload_result)",
f" def for_jit{sig_str}:",
f" task_begin(domain, handle)",
f" return_value = result({args_str})",
f" task_end(domain)",
f" return return_value",
f" return for_jit"]

func_text = '\n'.join(func_lines)
global_vars = {"func": func,
"numba": numba,
"domain": domain,
"handle": handle,
"task_begin": task_begin,
"task_end": task_end
}

return func_text, global_vars


def exec_impl(func, handle):
func_text, global_vars = codegen_exec_impl(func, handle)
loc_vars = {}
exec(func_text, global_vars, loc_vars)
_impl = loc_vars['wrapper']

return _impl