public void bbb()
{
}
public void aaa()
{
bbb();
}
public void bench1()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
aaa();
}
}
}
и получаю 8000ms;
если делаю методы aaa и bbb виртуальными,
получаю 2200ms;
если делаю методы статическими,
получаю 2000ms;
в чем проблема?
ведь исходный вариант, по идее, должен был бы где-то посередине лежать.
Release Build.
Здравствуйте _vovin, Вы писали:
V>Неужели никто не может запустить и посмотреть? V>Что-то совсем плох CLR по поводу скорости. Или каких-то оптимизаций не хватает?
Здравствуйте _vovin, Вы писали:
L>>Вот мои результаты (в тиках)
V>[...]
L>> L>>Как и ожидалось.
V>Я исходник можно? V>В чем компилировал, какие дополнительные опции выставлял?
using System;
namespace ConsoleApplication1
{
class Class1
{
private class Bench1
{
public void bbb()
{
}
public void aaa()
{
bbb();
}
public void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
aaa();
}
}
}
}
private class Bench2
{
public virtual void bbb()
{
}
public virtual void aaa()
{
bbb();
}
public virtual void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
aaa();
}
}
}
}
private class Bench3
{
public static void bbb()
{
}
public static void aaa()
{
bbb();
}
public void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
Bench3.aaa();
}
}
}
}
[STAThread]
static void Main(string[] args)
{
{
Bench1 t = new Bench1();
DateTime t1 = DateTime.Now;
t.bench();
DateTime t2 = DateTime.Now;
Console.WriteLine(t2.Ticks-t1.Ticks);
Console.ReadLine();
}
{
Bench2 t = new Bench2();
DateTime t1 = DateTime.Now;
t.bench();
DateTime t2 = DateTime.Now;
Console.WriteLine(t2.Ticks-t1.Ticks);
Console.ReadLine();
}
{
Bench3 t = new Bench3();
DateTime t1 = DateTime.Now;
t.bench();
DateTime t2 = DateTime.Now;
Console.WriteLine(t2.Ticks-t1.Ticks);
Console.ReadLine();
}
}
}
}
Да, любопытно.
С этим примером у меня получилось
530ms — обычный метод,
2030ms — виртуальный,
510ms — статический.
Должен сказать, что средняя цифра не впечатляет.
Современные системы отличаются высокой степенью полиморфизма алгоритмов,
в частности, в задачах CAE, которые я решаю, выполняется множество полиморфных
вызовов на большом множестве объектов. И тут узким местом является вызов
виртуальных методов.
По результатам видно, что C# тут не силен.
Я сделал аналогичный пример для языка Smalltalk. Он отличается тем, что каждая
посылка сообщения вызывает динамическую диспетчеризацию, это намного более тяжелая
операция чем вызов виртуального метода в C#. Но стандартные в этой области приемы
оптимизации вызовов позволяют достичь хороших результатов.
Т.е. полиморфные динамически-диспетчеризуемые вызовы Smalltalk быстрее виртуальных
статически-диспетчеризуемых вызовов C#. А Strongtalk приближается по скорости и к
статических вызовам.
Похоже, разработчикам предстоит еще много работы, чтобы поднять производительность
C# до победного уровня.
P.S. Когда выходит новый язык, то сразу появляются сравнения производительности с
другими языками. Но тесты ограничиваются a = b + c; b = a * c. Но это по сути
сравнение фортранов, а не современных языков.
Если язык называется объектно-ориентированным, то я думаю, нужно тестировать
его соответствующие характеристики?
V>Да, любопытно. V>С этим примером у меня получилось V>530ms — обычный метод, V>2030ms — виртуальный, V>510ms — статический.
V>VisualWorks Smalltalk 7 — 1500ms V>Strongtalk 1.1 — 700ms
Заметь, максимум двухлетний .net (на самом-то деле однолетний) дает резльтат, близкий к 20 летнему
смолтоку (2030ms <> 1500ms).
Учитывая, что .net становится основным средством разработки под самую популярную и широкорасространненую ос, следует ожидать, что мс в следующих версиях переплюнет уж смолток по производительности (жабу уже сделали ).
V>Т.е. полиморфные динамически-диспетчеризуемые вызовы Smalltalk быстрее виртуальных V>статически-диспетчеризуемых вызовов C#. А Strongtalk приближается по скорости и к V>статических вызовам.
С чего ты взял, что в с# виртуальные вызовы реализованы как static dispatch? Как это вообще можно сделать для виртуальных вызовов? Ну наверное как-то можно, но только в с# они как раз dynamic dispatch.
V>Похоже, разработчикам предстоит еще много работы, чтобы поднять производительность V>C# до победного уровня.
V>P.S. Когда выходит новый язык, то сразу появляются сравнения производительности с V>другими языками. Но тесты ограничиваются a = b + c; b = a * c. Но это по сути V>сравнение фортранов, а не современных языков. V> Если язык называется объектно-ориентированным, то я думаю, нужно тестировать V>его соответствующие характеристики?
Здравствуйте MaxMP, Вы писали:
V>>Да, любопытно. V>>С этим примером у меня получилось V>>530ms — обычный метод, V>>2030ms — виртуальный, V>>510ms — статический.
V>>VisualWorks Smalltalk 7 — 1500ms V>>Strongtalk 1.1 — 700ms
MMP>Заметь, максимум двухлетний .net (на самом-то деле однолетний) дает резльтат, близкий к 20 летнему MMP>смолтоку (2030ms <> 1500ms).
.NET наследует наработки C/C++/J++ компиляторов,
а это очень долгая история.
Smalltalk изначально был интерпретируемым,
экспериментальные динамические компиляторы
начали появляться году в 1984-ом.
Первый коммерческий динамический компилятор
появился где-то в 1993-ем.
MMP>Учитывая, что .net становится основным средством разработки под самую популярную и широкорасространненую ос, следует ожидать, что мс в следующих версиях переплюнет уж смолток по производительности (жабу уже сделали ).
Неплохо было бы посмотреть виртуальные вызовы
на JVM 1.4. У меня есть подозрение, что тут не
сделали.
V>>Т.е. полиморфные динамически-диспетчеризуемые вызовы Smalltalk быстрее виртуальных V>>статически-диспетчеризуемых вызовов C#. А Strongtalk приближается по скорости и к V>>статических вызовам.
MMP>С чего ты взял, что в с# виртуальные вызовы реализованы как static dispatch? Как это вообще можно сделать для виртуальных вызовов? Ну наверное как-то можно, но только в с# они как раз dynamic dispatch.
Dynamic binding но static vtable-based dispatch.
В Smalltalk dynamic binding и dynamic dispatch.
Разница ощущается?
Еще стоит измерить скорость reflection, тут
уже будет существенный разрыв.
V>>Похоже, разработчикам предстоит еще много работы, чтобы поднять производительность V>>C# до победного уровня.
V>>P.S. Когда выходит новый язык, то сразу появляются сравнения производительности с V>>другими языками. Но тесты ограничиваются a = b + c; b = a * c. Но это по сути V>>сравнение фортранов, а не современных языков. V>> Если язык называется объектно-ориентированным, то я думаю, нужно тестировать V>>его соответствующие характеристики?
V>Неплохо было бы посмотреть виртуальные вызовы V>на JVM 1.4. У меня есть подозрение, что тут не V>сделали.
bench.cs:
using System;
namespace ConsoleApplication1
{
class Bench2 : PreBench2
{
public override void bbb()
{
}
}
class PreBench2
{
public virtual void bbb()
{
}
public virtual void aaa()
{
bbb();
}
public virtual void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
aaa();
}
}
}
}
class Class1
{
private class Bench1
{
public void bbb()
{
}
public void aaa()
{
bbb();
}
public void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
aaa();
}
}
}
}
private class Bench3
{
public static void bbb()
{
}
public static void aaa()
{
bbb();
}
public void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
Bench3.aaa();
}
}
}
}
[STAThread]
static void Main(string[] args)
{
{
Bench1 t = new Bench1();
DateTime t1 = DateTime.Now;
t.bench();
DateTime t2 = DateTime.Now;
Console.WriteLine(t2-t1);
}
{
Bench2 t = new Bench2();
DateTime t1 = DateTime.Now;
t.bench();
DateTime t2 = DateTime.Now;
Console.WriteLine(t2-t1);
}
{
Bench3 t = new Bench3();
DateTime t1 = DateTime.Now;
t.bench();
DateTime t2 = DateTime.Now;
Console.WriteLine(t2-t1);
}
}
}
}
ClassA.java:
import java.util.*;
public class ClassA
{
public static void main(String[] args)
{
{
Bench1 t = new Bench1();
long t1 = new Date().getTime();
t.bench();
long t2 = new Date().getTime();
System.out.println(t2-t1);
}
{
Bench2 t = new Bench2();
long t1 = new Date().getTime();
t.bench();
long t2 = new Date().getTime();
System.out.println(t2-t1);
}
{
Bench3 t = new Bench3();
long t1 = new Date().getTime();
t.bench();
long t2 = new Date().getTime();
System.out.println(t2-t1);
}
}
}
class Bench1
{
final public void bbb()
{
}
final public void aaa()
{
bbb();
}
final public void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
aaa();
}
}
}
}
class Bench2 extends PreBench2
{
public void bbb()
{
}
}
class PreBench2
{
public void bbb()
{
}
public void aaa()
{
bbb();
}
public void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
aaa();
}
}
}
}
class Bench3
{
public static void bbb()
{
}
public static void aaa()
{
bbb();
}
public void bench()
{
int n = 10000;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
Bench3.aaa();
}
}
}
}
А ты еще на С++ применчик сделай. Увидишь, что они и от него не сильно отстают. Просто моногие С++-компиляторы могут понять что дествия бесполезны и выбростить цыклы и вызовы. Посмотри шустриков... Там результаты разных компиляторов: http://rsdn.ru/article/?devtools/perftest.xml
Здравствуйте VladD2, Вы писали:
VD>Здравствуйте Lloyd, Вы писали:
VD>Вместо DateTime.Now лучше использовать Environment.TickCount. Это куда точнее.
VD>
Цыфры в данном случае совершенно никакого значения не имеют. Важно соотношение величин.
Здравствуйте VladD2, Вы писали:
VD>А ты еще на С++ применчик сделай. Увидишь, что они и от него не сильно отстают. Просто моногие С++-компиляторы могут понять что дествия бесполезны и выбростить цыклы и вызовы. Посмотри шустриков... Там результаты разных компиляторов: VD>http://rsdn.ru/article/?devtools/perftest.xml
Здравствуйте MaxMP, Вы писали:
V>>Неплохо было бы посмотреть виртуальные вызовы V>>на JVM 1.4. У меня есть подозрение, что тут не V>>сделали.
MMP>bench.cs: MMP>
Спасибо за результаты.
Хотя это не то, что я ожидал увидеть.
HotSpot JVM тратит дополнительное время
на адаптивное определение "горячих точек".
Но плохо то, что она не оптимизирует
виртуальные вызовы (по-крайней мере не в
этом примере).
А ведь HotSpot является непосредственным
потомком Strongtalk Virtual Machine для
языка Java.
Видно в ней не полностью реализован
Polymorphic Inline Cache.
Как известно, рефлексия очень сильно используется
в распределенным приложениях.
Вот еще один параметр производительности.
И вот почему целочисленные тесты ничего не говорят
о поведении приложения в реальных условиях.
P.S. Кто-нибудь может еще результаты JDK1.4 привести?
Здравствуйте VladD2, Вы писали:
VD>Здравствуйте MaxMP, Вы писали:
VD> MMP>>D:\My Documents\DotNet.exp\Exp\JavaVsC#\virtualPerf>bench MMP>>00:00:00.2002880 MMP>>00:00:01.3419296 MMP>>00:00:00.2002880
MMP>> MMP>>javac ClassA.java MMP>>D:\My Documents\DotNet.exp\Exp\JavaVsC#\virtualPerf>java ClassA
MMP>>370 MMP>>1933 MMP>>411
MMP>>Так что сделали.
MMP>>PS. JDK 1.4
VD>А ты еще на С++ применчик сделай. Увидишь, что они и от него не сильно отстают. Просто моногие С++-компиляторы могут понять что дествия бесполезны и выбростить цыклы и вызовы. Посмотри шустриков... Там результаты разных компиляторов: VD>http://rsdn.ru/article/?devtools/perftest.xml
V>Еще раз воспроизведу свои результаты:
V>C# — 530/2030 (прямой/виртуальный) V>VC6 — 1370/1550
V>VisualWorks — 1500 V>Strongtalk — 700
V>М-да. Но результат вполне согласуется с теорией. V>Только вот VC6 что-то подкачал на прямом вызове. V>Видимо, C# исключает внутренний вызов, а VC6 нет.
Ты просто не добавил в VC6 опцию /Ob2. Если добавишь, то все встанет на свои места.
PS
Ты на VB6 перепиши. Вот посмешся. По большому счету ведь Шарп с VB нужно сравнивать. Ведь простота разработки у него больше на VB походит, чем на С++.
Здравствуйте iZEN, Вы писали:
ZEN>Здравствуйте VladD2, Вы писали:
VD>>А ты еще на С++ применчик сделай. Увидишь, что они и от него не сильно отстают. Просто моногие С++-компиляторы могут понять что дествия бесполезны и выбростить цыклы и вызовы. Посмотри шустриков... Там результаты разных компиляторов: VD>>http://rsdn.ru/article/?devtools/perftest.xml
Здравствуйте _vovin, Вы писали:
V>Как известно, рефлексия очень сильно используется V>в распределенным приложениях. V>Вот еще один параметр производительности. V>И вот почему целочисленные тесты ничего не говорят V>о поведении приложения в реальных условиях.
Ты вот задумайся... насколько ничтожно будет выглядеть тормоза рефлекшона по сравнению с маршалингом? Мы вот тут проверяли и огазаолось, что за маршалингом уже никакие тормоза средств разработки не видны. В сети все на пордки тормозней.
Здравствуйте Lloyd, Вы писали:
L>Здравствуйте VladD2, Вы писали:
VD>>Здравствуйте Lloyd, Вы писали:
VD>>Вместо DateTime.Now лучше использовать Environment.TickCount. Это куда точнее.
L>Цыфры в данном случае совершенно никакого значения не имеют. Важно соотношение величин.
В любом случае мерять лучше Environment.TickCount-ом.