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

smr888 picture smr888  路  38Comments

Nichtraucher picture Nichtraucher  路  42Comments

danroth27 picture danroth27  路  39Comments

grendello picture grendello  路  33Comments

EddaAkikusa picture EddaAkikusa  路  34Comments