import sys

from clpy.cuda import memory_hook


class DebugPrintHook(memory_hook.MemoryHook):
    """Memory hook that prints debug information.

    This memory hook outputs the debug information of input arguments of
    ``malloc`` and ``free`` methods involved in the hooked functions
    at postprocessing time (that is, just after each method is called).

    Example:
        The basic usage is to use it with ``with`` statement.

        Code example::

            >>> import clpy
            >>> from clpy.cuda import memory_hooks
            >>>
            >>> clpy.cuda.set_allocator(clpy.cuda.MemoryPool().malloc)
            >>> with memory_hooks.DebugPrintHook():
            ...     x = clpy.array([1, 2, 3])
            ...     del x  # doctest:+SKIP

        Output example::

            {"hook":"alloc","device_id":0,"mem_size":512,"mem_ptr":150496608256}
            {"hook":"malloc","device_id":0,"size":24,"mem_size":512,"mem_ptr":150496608256,"pmem_id":"0x7f39200c5278"}
            {"hook":"free","device_id":0,"mem_size":512,"mem_ptr":150496608256,"pmem_id":"0x7f39200c5278"}

        where the output format is JSONL (JSON Lines) and
        ``hook`` is the name of hook point, and
        ``device_id`` is the CUDA Device ID, and
        ``size`` is the requested memory size to allocate, and
        ``mem_size`` is the rounded memory size to be allocated, and
        ``mem_ptr`` is the memory pointer, and
        ``pmem_id`` is clpy.cuda.memory.PooledMemory object ID.

    Attributes:
        file: Output file_like object that redirect to.
        flush: If ``True``, this hook forcibly flushes the text stream
            at the end of print. The default is ``True``.

    """

    name = 'DebugPrintHook'

    def __init__(self, file=sys.stdout, flush=True):
        self.file = file
        self.flush = flush

    def _print(self, msg):
        self.file.write(msg)
        self.file.write('\n')
        if self.flush:
            self.file.flush()

    def alloc_postprocess(self, **kwargs):
        msg = '{"hook":"%s","device_id":%d,' \
              '"mem_size":%d,"mem_ptr":%d}'
        msg %= ('alloc', kwargs['device_id'],
                kwargs['mem_size'], kwargs['mem_ptr'])
        self._print(msg)

    def malloc_postprocess(self, **kwargs):
        msg = '{"hook":"%s","device_id":%d,"size":%d,' \
              '"mem_size":%d,"mem_ptr":%d,"pmem_id":"%s"}'
        msg %= ('malloc', kwargs['device_id'], kwargs['size'],
                kwargs['mem_size'], kwargs['mem_ptr'], hex(kwargs['pmem_id']))
        self._print(msg)

    def free_postprocess(self, **kwargs):
        msg = '{"hook":"%s","device_id":%d,' \
              '"mem_size":%d,"mem_ptr":%d,"pmem_id":"%s"}'
        msg %= ('free', kwargs['device_id'],
                kwargs['mem_size'], kwargs['mem_ptr'], hex(kwargs['pmem_id']))
        self._print(msg)

import sys

from clpy.cuda import memory_hook


class DebugPrintHook(memory_hook.MemoryHook):
    """Memory hook that prints debug information.

    This memory hook outputs the debug information of input arguments of
    ``malloc`` and ``free`` methods involved in the hooked functions
    at postprocessing time (that is, just after each method is called).

    Example:
        The basic usage is to use it with ``with`` statement.

        Code example::

            >>> import clpy
            >>> from clpy.cuda import memory_hooks
            >>>
            >>> clpy.cuda.set_allocator(clpy.cuda.MemoryPool().malloc)
            >>> with memory_hooks.DebugPrintHook():
            ...     x = clpy.array([1, 2, 3])
            ...     del x  # doctest:+SKIP

        Output example::

            {"hook":"alloc","device_id":0,"mem_size":512,"mem_ptr":150496608256}
            {"hook":"malloc","device_id":0,"size":24,"mem_size":512,"mem_ptr":150496608256,"pmem_id":"0x7f39200c5278"}
            {"hook":"free","device_id":0,"mem_size":512,"mem_ptr":150496608256,"pmem_id":"0x7f39200c5278"}

        where the output format is JSONL (JSON Lines) and
        ``hook`` is the name of hook point, and
        ``device_id`` is the CUDA Device ID, and
        ``size`` is the requested memory size to allocate, and
        ``mem_size`` is the rounded memory size to be allocated, and
        ``mem_ptr`` is the memory pointer, and
        ``pmem_id`` is clpy.cuda.memory.PooledMemory object ID.

    Attributes:
        file: Output file_like object that redirect to.
        flush: If ``True``, this hook forcibly flushes the text stream
            at the end of print. The default is ``True``.

    """

    name = 'DebugPrintHook'

    def __init__(self, file=sys.stdout, flush=True):
        self.file = file
        self.flush = flush

    def _print(self, msg):
        self.file.write(msg)
        self.file.write('\n')
        if self.flush:
            self.file.flush()

    def alloc_postprocess(self, **kwargs):
        msg = '{"hook":"%s","device_id":%d,' \
              '"mem_size":%d,"mem_ptr":%d}'
        msg %= ('alloc', kwargs['device_id'],
                kwargs['mem_size'], kwargs['mem_ptr'])
        self._print(msg)

    def malloc_postprocess(self, **kwargs):
        msg = '{"hook":"%s","device_id":%d,"size":%d,' \
              '"mem_size":%d,"mem_ptr":%d,"pmem_id":"%s"}'
        msg %= ('malloc', kwargs['device_id'], kwargs['size'],
                kwargs['mem_size'], kwargs['mem_ptr'], hex(kwargs['pmem_id']))
        self._print(msg)

    def free_postprocess(self, **kwargs):
        msg = '{"hook":"%s","device_id":%d,' \
              '"mem_size":%d,"mem_ptr":%d,"pmem_id":"%s"}'
        msg %= ('free', kwargs['device_id'],
                kwargs['mem_size'], kwargs['mem_ptr'], hex(kwargs['pmem_id']))
        self._print(msg)

Memory hook that prints debug information.      This memory hook outputs the debug information of input arguments of     ``malloc`` and ``free`` methods involved in the hooked functions     at postprocessing time (that is, just after each method is called).      Example:         The basic usage is to use it with ``with`` statement.          Code example::              >>> import clpy             >>> from clpy.cuda import memory_hooks             >>>             >>> clpy.cuda.set_allocator(clpy.cuda.MemoryPool().malloc)             >>> with memory_hooks.DebugPrintHook():             ...     x = clpy.array([1, 2, 3])             ...     del x  # doctest:+SKIP          Output example::              {"hook":"alloc","device_id":0,"mem_size":512,"mem_ptr":150496608256}             {"hook":"malloc","device_id":0,"size":24,"mem_size":512,"mem_ptr":150496608256,"pmem_id":"0x7f39200c5278"}             {"hook":"free","device_id":0,"mem_size":512,"mem_ptr":150496608256,"pmem_id":"0x7f39200c5278"}          where the output format is JSONL (JSON Lines) and         ``hook`` is the name of hook point, and         ``device_id`` is the CUDA Device ID, and         ``size`` is the requested memory size to allocate, and         ``mem_size`` is the rounded memory size to be allocated, and         ``mem_ptr`` is the memory pointer, and         ``pmem_id`` is clpy.cuda.memory.PooledMemory object ID.      Attributes:         file: Output file_like object that redirect to.         flush: If ``True``, this hook forcibly flushes the text stream             at the end of print. The default is ``True``.