Mono: Why call c native function with string or float args from c# cost so many time?

Created on 18 Jan 2019  路  2Comments  路  Source: mono/mono

I make test for internal call pass difference args:

The cost with call 100000 times result is:

pass (str, int, float): 1020ms
pass(int, float): 900ms
pass(int, int): 200ms

The C# side code:

``` C#

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void TestPassValueWithStrIntFloat(string a, int b, float c);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void TestPassValueWithIntFloat(int b, float c);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void TestPassValueWithIntInt(int b, int c);

saw = Stopwatch.StartNew();
sw.Start();
string str = "111";
for(int i = 0;i < 999999; i++)
{
TestPassValueWithStrIntFloat(str, 1, 1.0f);
}
sw.Stop();
Console.WriteLine(String.Format("test_c_func_set_value_with_str_int_float, Time taken: {0}ms", sw.Elapsed.TotalMilliseconds));

sw = Stopwatch.StartNew();
sw.Start();
for(int i = 0;i < 999999; i++)
TestPassValueWithIntFloat(1, 1.0f);
sw.Stop();
Console.WriteLine(String.Format("test_c_func_set_value_with_int_float, Time taken: {0}ms", sw.Elapsed.TotalMilliseconds));

sw = Stopwatch.StartNew();
sw.Start();
for(int i = 0;i < 999999; i++)
TestPassValueWithIntInt(1, 1);
sw.Stop();
Console.WriteLine(String.Format("test_c_func_set_value_with_int_int, Time taken: {0}ms", sw.Elapsed.TotalMilliseconds));


## The C side code:

``` c

void TestPassValueWithStrIntFloat(MonoString* text, int a, float b)
{

}

void TestPassValueWithIntFloat(int a, float b)
{

}

void TestPassValueWithIntInt(int a, int b)
{

}

// add internal_call
mono_add_internal_call("TestRunner::TestPassValueWithStrIntFloat", TestPassValueWithStrIntFloat);
mono_add_internal_call("TestRunner::TestPassValueWithIntFloat", TestPassValueWithIntFloat);
mono_add_internal_call("TestRunner::TestPassValueWithIntInt", TestPassValueWithIntInt);

And the mono init setup mode:

void mono_ios_setup_execution_mode (void)
{
    mono_icall_table_init ();
    mono_marshal_ilgen_init ();
    mono_method_builder_ilgen_init ();
    mono_sgen_mono_ilgen_init ();
    mono_ee_interp_init (0);
    mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP);
}

The cost output:

2019-01-18 12:04:22.954022+0800 RunMonoOniOS[78000:6466784] [stdout] test_c_func_set_value_with_str_int_float, Time taken: 1020.8563ms
2019-01-18 12:04:23.869507+0800 RunMonoOniOS[78000:6466784] [stdout] test_c_func_set_value_with_int_float, Time taken: 915.0514ms
2019-01-18 12:04:24.073775+0800 RunMonoOniOS[78000:6466784] [stdout] test_c_func_set_value_with_int_int, Time taken: 203.8157ms

question

Most helpful comment

@srxqds I am assuming the main slowness comes from passing the floating argument. On the interpreter we only optimise native calls that use the general registers. If you are passing a float argument we fallback to a slower, general path. You could avoid this by passing the floating value by reference, or somehow pass it by value but as an integer.

Passing managed objects can also produce additional overhead.

All 2 comments

@migueldeicaza can you help me?
why and how can I make the optimization?

thank you !

@srxqds I am assuming the main slowness comes from passing the floating argument. On the interpreter we only optimise native calls that use the general registers. If you are passing a float argument we fallback to a slower, general path. You could avoid this by passing the floating value by reference, or somehow pass it by value but as an integer.

Passing managed objects can also produce additional overhead.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HeikoWeiss picture HeikoWeiss  路  5Comments

DanielCauser picture DanielCauser  路  4Comments

EgorBo picture EgorBo  路  3Comments

JoseTiagoCarvalho picture JoseTiagoCarvalho  路  3Comments

pjeutr picture pjeutr  路  5Comments