Hans
Hans

Reputation: 2262

Converting Objective-C code to Delphi (XE8)

To trace how much memory various parts of my code allocates, I found this objective-C code (here), that I want to run in Delphi XE8:

void report_memory(void)
{
    struct mach_task_basic_info info;
    mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
    kern_return_t kerr = task_info(mach_task_self(),
                                   MACH_TASK_BASIC_INFO,
                                   (task_info_t)&info,
                                   &size);
    if( kerr == KERN_SUCCESS ) {
        NSLog(@"Memory in use (in bytes): %u", info.resident_size);
    }
}

This code simply reads the current amount of memory used by the program and logs it. I will use it to detect how much memory usage grows when calling different parts of my code.

It includes Mach.h, and there is a Macapi.Mach.pas unit in Delphi, but it does not implement any of the definitions used here.

(The NSLog function log is implemented already: iOSApi.Foundation.NSLog((StrToNSStr(aMessage) as ILocalObject).GetObjectID))

How should this code be converted to Delphi XE8? (I might be able to convert the definitions my self, but where do I find the headers?)

PS. I know this is a primitive way of tracing memory, but I have not found any better solution. The Xcode Instruments, tells me that my app calls malloc 180.000 times, but it does not indicate what code or objects initiated it. This information might be lost because I use Delphi.

Update

Here is my translation and implementation of the function. It works with the iOS simulator and when targeting a 32bit iOS device, but it does NOT work on a 64 bit iOS device (return value is 4).

unit uMachExt;

interface

uses Macapi.Mach, Posix.Base;

type
  integer_t = Integer;
  natural_t = NativeInt;
  mach_vm_size_t = UInt64;
  //typedef int policy_t
  policy_t = Integer;

  //type time_value_t = struct[2] of integer_t;
  time_value_t = array[0..1] of Integer; //0:seconds, 1:microseconds

  //typedef natural_t mach_msg_type_number_t
  mach_msg_type_number_t = natural_t;

  //type kern_return_t = int;
  kern_return_t = integer;

  //typedef natural_t   task_flavor_t;
  task_flavor_t = natural_t;

  // typedef    integer_t   *task_info_t;       /* varying array of int */
  task_info_t = array of integer_t;

  {#define MACH_TASK_BASIC_INFO     20         /* always 64-bit basic info */
  struct mach_task_basic_info {
          mach_vm_size_t  virtual_size;       /* virtual memory size (bytes) */
          mach_vm_size_t  resident_size;      /* resident memory size (bytes) */
          mach_vm_size_t  resident_size_max;  /* maximum resident memory size (bytes) */
          time_value_t    user_time;          /* total user run time for
                                                 terminated threads */
          time_value_t    system_time;        /* total system run time for
                                                 terminated threads */
          policy_t        policy;             /* default policy for new threads */
          integer_t       suspend_count;      /* suspend count for task */
  }
  mach_task_basic_info = Record
        virtual_size: mach_vm_size_t  ;       //* virtual memory size (bytes) */
        resident_size: mach_vm_size_t  ;      //* resident memory size (bytes) */
        resident_size_max: mach_vm_size_t  ;  //* maximum resident memory size (bytes) */
        user_time: time_value_t    ;          //* total user run time for terminated threads */
        system_time: time_value_t    ;        //* total system run time forterminated threads */
        policy: policy_t        ;             //* default policy for new threads */
        suspend_count: integer_t;               //* suspend count for task */
  end;

const
  cMACH_TASK_BASIC_INFO = 20;
  {typedef struct mach_task_basic_info       mach_task_basic_info_data_t;
  #define MACH_TASK_BASIC_INFO_COUNT   \
                (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))}
  cMACH_TASK_BASIC_INFO_COUNT = SizeOf(mach_task_basic_info) div sizeof(natural_t);

  {
  #ifdef    mig_external
  mig_external
  #else
  extern
  #endif    /* mig_external */
  kern_return_t task_info
  (
    task_name_t target_task,
    task_flavor_t flavor,
    task_info_t task_info_out,
    mach_msg_type_number_t *task_info_outCnt
  );
  }

  function task_info( target_task: task_name_t;
                      flavor: task_flavor_t;
                      var task_info_out: mach_task_basic_info;
                      var task_info_outCnt: mach_msg_type_number_t)  : kern_return_t;
    cdecl external libc name _PU + 'task_info';

  function GetMemoryUsage: Integer;

implementation

{   struct mach_task_basic_info info;
    mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT;
    kern_return_t kerr = task_info(mach_task_self(),
                                   MACH_TASK_BASIC_INFO,
                                   (task_info_t)&info,
                                   &size);
}

function GetMemoryUsage: Integer;
var info: mach_task_basic_info;
    size: mach_msg_type_number_t;
    kerr: kern_return_t;
begin
  Result := 0;
  size := cMACH_TASK_BASIC_INFO_COUNT;
  kerr := task_info(mach_task_self, cMACH_TASK_BASIC_INFO, info, size);
  if kerr=0 then
    result := info.resident_size;
end;

end.

It is enough for me that it works with 32 bit, but for completeness, if you find what should be changed to make it work with 64 bit, please comment (also if you find other errors in the implementation).

Upvotes: 2

Views: 688

Answers (1)

Sebastian Z
Sebastian Z

Reputation: 4730

You can find the headers in the subfolders of /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer.

I like to copy these to another folder on my HDD in order to keep old versions of an SDK that is not included in the current version of XCode. That way I can also use Spotlight in order to quickly find the file that contains a specific function or definition.

Upvotes: 2

Related Questions