Сравнительные тесты скорости расчетов типов данных

Оптимизация кода.

Сравнительные тесты скорости расчетов типов данных

Сообщение bwolf88 29 ноя 2014, 20:09

Провел небольшие сравнительные тесты расчетов некоторых типов данных, а также скорость доступа к массивам. Тесты проводились путем зажатия кнопки в Update и использования обычной статистики unity ;;).

Синтаксис:
Используется csharp

//assTest--------------
    int iA;
    int iB = 12;

    //arrayTest-----------------
    int[,] arr1 = new int[2,2]{{1,4},{2,7}};
    int[] arr2 = new int[4] {1, 4, 2, 7};
    object[] arr3 = new object[4] { 1, "a", new Vector3(1, 1, 0), 5 };
    int arB;

    //Vector3 test
    Vector3[] arr4 = new Vector3[] { new Vector3(0, 1, 1), new Vector3 ( -1, 0, 0 ), new Vector3 ( 2, 0, 0 ) };
    Vector3 vAr1;
    Vector3 vAr2 = new Vector3(1, 0, 0);
    Vector3 vAr3 = new Vector3(2, 4, 5);
    float vx, vy, vz;

    void Update()
    {
        ControlTest();
    }

    void testExample()
    {
        Stopwatch st = new Stopwatch(); TimeSpan ts; st.Start();

        st.Stop(); ts = st.Elapsed; print(ts);
    }

    #region AssignedTest

    void AssT1()
    {
        for (int i = 0; i < 10000000; i++)
        {
            iA = 12;
        }
        //48ms
    }

    void AssT2()
    {
        for (int i = 0; i < 10000000; i++)
        {
            iA = iB;
        }
        //53ms
    }

    void AssT3()
    {
        for (int i = 0; i < 10000000; i++)
        {
            iA = AssT4();
        }
        //130ms
    }

    int AssT4()
    {
        return 12;
    }

    #endregion

    #region ArrayTest

    void ArrT1()
    {
        for (int i = 0; i < 10000000; i++)
        {
            arB = arr1[1, 1];
        }
        //133ms
    }

    void ArrT2()
    {
        for (int i = 0; i < 10000000; i++)
        {
            arB = arr2[2];
        }
        //51ms
    }

    void ArrT3() // ----------приемлемый вариант
    {
        for (int i = 0; i < 10000000; i++)
        {
            int ind1 = 2*18;
            arB = arr2[1 + 1];
        }
        //64ms
    }

    void ArrT4()
    {
        for (int i = 0; i < 10000000; i++)
        {
            arB = (int)arr3[0];
        }
        //74ms
    }

    #endregion

    #region Vector3Test
    void VecT1()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1 = (Vector3)arr4[0];
        }
        //90ms
    }

    void VecT2()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1 = Vector3.right;
        }

        //295ms
    }
    void VecT3()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1 = new Vector3(1, 0, 2);
        }

        //220ms
    }

    void VecT4()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1 = vAr2;
        }
        //72ms
    }

    void VecT5()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vx = vAr2.x+12.1f;
            vy = vAr2.y+13.2f;
            vz = vAr2.z+14.5f;
            vAr1.x = vx;
            vAr1.y = vy;
            vAr1.z = vz;
        }
        //173ms
    }

    void VecT6() //приемлемый
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1.x = vAr2.x + 12.1f;
            vAr1.y = vAr2.y + 13.2f;
            vAr1.z = vAr2.z + 14.5f;
        }
        //101ms
    }

    void VecT7()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1.x = vAr2.x + vAr3.x;
            vAr1.y = vAr2.y + vAr3.y;
            vAr1.z = vAr2.z + vAr3.z;
        }
        //119ms
    }

    void VecT8()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1 = vAr2 + new Vector3(1, 5, 4);
        }
        //510ms
    }

    void VecT9()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1 = vAr2 + vAr3;
        }
        //388ms
    }

    void VecT10()
    {
        for (int i = 0; i < 10000000; i++)
        {
            vAr1 = vAr2 + Vector3.right;
        }
        //610ms
    }

    #endregion

    void ControlTest()
    {
        if (Input.GetMouseButton(0))
        {
            VecT10();
        }    
        if (Input.GetMouseButton(1))
        {
            VecT8();
        }
        if (Input.GetKey(KeyCode.LeftControl))
        {
            VecT3();
        }
        if (Input.GetKey(KeyCode.LeftShift))
        {
            VecT4();
        }
    }

 


Что можно увидеть:
1. Одномерный массив с множителем почти в 2 раза быстрее любого многомерного массива.
2. Готовые конструкции типа Vector3.zero, Vector3.up на порядок медленнее заготовленных векторов и немного медленее new Vector(x,y,z) (только что созданных векторов)
3. Складывать, вычитать векторы в 3,5 раза медленее (готовые), в 5 раз медленее (если есть только что созданный вектор), и в 6 раз медленнее (если Vector3.up/right и т.п.), чем проводить те же операции с их индексами.
4. Получение значения используя другой метод того же типа, что и переменная в 2 раза медленее чем получать значение, вычисляя его в самом методе.
5. На счет того, что списки в 2 раза медленнее массивов, думаю говорить не нужно :).

Если у кого есть подобные тесты производительности или уже готовые решения повышающие скорость вычислений - прошу не стесняться выкладывать, мне очень нужна подобная информация.
Сюда периодически чего нибудь выкладываю https://github.com/LuchunPen
Аватара пользователя
bwolf88
Адепт
 
Сообщения: 2184
Зарегистрирован: 30 апр 2014, 06:40
Skype: bwolf331

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение Diab10 30 ноя 2014, 10:36

(3A4OT)
Аватара пользователя
Diab10
Адепт
 
Сообщения: 3401
Зарегистрирован: 17 мар 2011, 20:42
Откуда: 123 RUS
Skype: diab1023

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение Woolf 30 ноя 2014, 10:59

Мда..

Вот это вот вы что меряли?

Синтаксис:
Используется csharp
     for (int i = 0; i < 10000000; i++)
        {
            arB = arr1[1, 1];
        }


Ну и десятки других подобных "измерений" ? Если вы думаете, что вы таким образом меряли скорость работы с массивом - вы ошибаетесь.
Разработчик theFisherOnline - там, где клюёт
Разработчик Atom Fishing II - Первая 3D MMO про рыбалку
Разработчик Atom Fishing - Рыбалка на поплавок, донку, нахлыст, блесну в постъядерный период.
Аватара пользователя
Woolf
Адепт
 
Сообщения: 7179
Зарегистрирован: 02 мар 2009, 16:59

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение marikcool 30 ноя 2014, 13:52

это в windows standalone замеры?
или с эдитора вообще?
со статик векторами будут тесты?
зачем плюсовать Vector3.right, обычно на нормализованные вектора идет умножение. будут ли тесты на умножение?
marikcool
UNITрон
 
Сообщения: 174
Зарегистрирован: 05 дек 2012, 23:19

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение bwolf88 30 ноя 2014, 18:02

Woolf писал(а):Мда..

Вот это вот вы что меряли?

Синтаксис:
Используется csharp
     for (int i = 0; i < 10000000; i++)
        {
            arB = arr1[1, 1];
        }


Ну и десятки других подобных "измерений" ? Если вы думаете, что вы таким образом меряли скорость работы с массивом - вы ошибаетесь.



Скажем так, благодаря этим тестам я заменил многие вычисления и улучшил скорость обработки геометрии своего первоначального меша MarchingCubes почти в 2,5 раза :). В том числе и замена изначального массива треугольников с [256,16] на одномерный массив [4096], дал мне прирост скорости около 35% к первоначальной. И скорость построение кубического меша на 15% в 4 юньке и 20% в 5. Кстати что порадовало, меш коллайдер в 5 юньке обрабатывается в 2 раза быстрее, что частично решает некоторые мои проблемы :).

Это не полный вариант тестов, я делал еще около 20 подобных, но скрипты к сожалению не сохранял а менял походу. Но допустим еще одна фишка:
Доступ к статическому классу медленнее, чем доступ к статическому экземпляру класса монобех почти в 2 раза. То есть два класса

Синтаксис:
Используется csharp
public static class KLASS{ }

и

public class KLACC : Monobehaviour{
public static KLACC klacc = this; //к переменным этого варианта доступ быстрее, хз почему, я в тонкостях не разбирался, может потому что он вешается на объект.
}
Последний раз редактировалось bwolf88 30 ноя 2014, 18:18, всего редактировалось 3 раз(а).
Сюда периодически чего нибудь выкладываю https://github.com/LuchunPen
Аватара пользователя
bwolf88
Адепт
 
Сообщения: 2184
Зарегистрирован: 30 апр 2014, 06:40
Skype: bwolf331

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение bwolf88 30 ноя 2014, 18:11

Или еще пример:

У меня в коде порой можно было встретить вот такие конструкции, мне очень нравились потому что значительно сокращали код.

Синтаксис:
Используется csharp
float[] mass1 = new float[4];
Vector3[] mass2 = new Vector3[4];

float B = mass2[mass1[3]].x;
 

Но каждое такое вложение пропорционально убивает скорость, потому что вместо одного массива мы обращаемся к двум и т.д. Я теперь пытаюсь от них избавиться и по возможности не использовать.
Сюда периодически чего нибудь выкладываю https://github.com/LuchunPen
Аватара пользователя
bwolf88
Адепт
 
Сообщения: 2184
Зарегистрирован: 30 апр 2014, 06:40
Skype: bwolf331

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение YuliyF 01 дек 2014, 02:30

2. Готовые конструкции типа Vector3.zero, Vector3.up на порядок медленнее заготовленных векторов и немного медленее new Vector(x,y,z) (только что созданных векторов)

только это удивило.. я думал стандартные заготовки поскорее будут.
будем рады увидеть ещё различные тесты
YuliyF
UNIт
 
Сообщения: 59
Зарегистрирован: 03 окт 2011, 02:51

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение Woolf 01 дек 2014, 07:23

Скажем так, благодаря этим тестам я заменил многие вычисления и улучшил скорость обработки геометрии своего первоначального меша MarchingCubes почти в 2,5 раза :). В том числе и замена изначального массива треугольников с [256,16] на одномерный массив [4096], дал мне прирост скорости около 35% к первоначальной. И скорость построение кубического меша на 15% в 4 юньке и 20% в 5


Самовнушение? Никакой разницы между одномерными и двумерными массивами нет. Вообще. Собственно, они все представлены в виде одномерного в памяти. Вся разница в вычислении индекса, там надо сделать одно умножение и сложение, то-же, что делаете и вы, когда используете одномерный вместо двумерного. ПРАВИЛЬНЫЕ тесты это подтверждают. А судя по вашему коду вы меряете не скорости работы с массивами, а скорости выполнения циклов. Работы с массивом у вас в тестах нет никакой ни в одном из замеров.

Касаемо Vector.Zero и использование заранее заготовленного - а как вы хотели? Вы меряйте Vector.Zero с new Vector (0,0,0) и смотрите, что быстрее. А то вы сравниваете ..кхм с пальцем и удивляетесь, что результаты такие. Короче, ваши тесты ни о чем не говорят. В одниъ вы сравниваете несравнимые величины, в других меряете не то, что заявили и так далее.

PS Надеюсь, вы измеряли в билде, а не в юнити?
Разработчик theFisherOnline - там, где клюёт
Разработчик Atom Fishing II - Первая 3D MMO про рыбалку
Разработчик Atom Fishing - Рыбалка на поплавок, донку, нахлыст, блесну в постъядерный период.
Аватара пользователя
Woolf
Адепт
 
Сообщения: 7179
Зарегистрирован: 02 мар 2009, 16:59

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение Nicloay 01 дек 2014, 10:23

про одномерный и двумерный ты прав отчасти.
Там еще в 2мерном проходит одна лишняя проверка, не вышел ли индекс за рамки. так что все должно быть верно - что в c++ что с# вручную переносить 2мерный массив на одномерный будет быстрее. Как одно из подтверждении, посмотри, что во всех движках MVC матрицы задаются одномерным массивом.

Да и скорость работы - тебе бы посмотреть вызовы GC обычно перформанс возрастает когда GC меньше срабатывает (это как раз про пул объектов, и переиспользование старых переменных).
If you wish to make an apple pie from scratch, you must first invent the universe.(Carl Sagan, Cosmos)
| My Asset Store | coloring book | github | _wiki.unity3d.com | twitter | linkedin |
Аватара пользователя
Nicloay
Адепт
 
Сообщения: 1288
Зарегистрирован: 31 май 2012, 09:27
Откуда: Альпс
  • Сайт

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение bwolf88 01 дек 2014, 10:33

Самовнушение?

Я привел вам и пример и временные интервалы. Я интересуюсь процедурной геометрией, а она подразумевает миллионные итерации с ресурсоемкими вычислениями векторов, массивов и т.п. и с этими расчетами вычисления происходят быстрее. 1000 мешей 16х16х16 ячеек MC по обычной схеме обрабатывались порядка 30 секунд, теперь - чуть больше 5 секунд и это еще не предел. Наверное самовнушение.

А вообще, Вы как программист с огромным стажем, вместо того чтобы спорить, привели бы пару подобных лайфхаков, многие бы это оценили. К сожалению мой опыт программирования чуть больше полугода и у меня нет возможности с Вами спорить, поскольку знаний не хватит. Поэтому я пишу лишь то, что мне показывает статистика, не вникая во внутренности процесса :).

Пожалуй больше не стану писать на подобную тематику, кому нужно - тот сам дойдет.
Сюда периодически чего нибудь выкладываю https://github.com/LuchunPen
Аватара пользователя
bwolf88
Адепт
 
Сообщения: 2184
Зарегистрирован: 30 апр 2014, 06:40
Skype: bwolf331

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение Diab10 01 дек 2014, 11:42

bwolf88 писал(а):Пожалуй больше не стану писать на подобную тематику, кому нужно - тот сам дойдет.


Не слушайте никого, очень полезные данные :)

Не пойму к чему спорить, если это реально помогло снизить время расчётов.
Аватара пользователя
Diab10
Адепт
 
Сообщения: 3401
Зарегистрирован: 17 мар 2011, 20:42
Откуда: 123 RUS
Skype: diab1023

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение Woolf 01 дек 2014, 11:43

bwolf88 писал(а):
Самовнушение?

Я привел вам и пример и временные интервалы. Я интересуюсь процедурной геометрией, а она подразумевает миллионные итерации с ресурсоемкими вычислениями векторов, массивов и т.п. и с этими расчетами вычисления происходят быстрее. 1000 мешей 16х16х16 ячеек MC по обычной схеме обрабатывались порядка 30 секунд, теперь - чуть больше 5 секунд и это еще не предел. Наверное самовнушение.

А вообще, Вы как программист с огромным стажем, вместо того чтобы спорить, привели бы пару подобных лайфхаков, многие бы это оценили. К сожалению мой опыт программирования чуть больше полугода и у меня нет возможности с Вами спорить, поскольку знаний не хватит. Поэтому я пишу лишь то, что мне показывает статистика, не вникая во внутренности процесса :).

Пожалуй больше не стану писать на подобную тематику, кому нужно - тот сам дойдет.


Ваша ошибка в том, что, тестируя работу с массивами - вы не проводите никакой работы с массивом, вы просто присваиваете одной и той же переменной одно и тоже значение в цикле. Это неверно, оптимизатор просто вынесет это присваивание за пределы цикла. Странно, что у вас еще вообще цикл отработал, теоретически, оптимизатор должен был пустой цикл убрать. Для более точного тестирования вы лучше делайте какую либо работу, например, подсчитайте сумму всех элементов масива.

А лайфхаки - рецептов тут всего два. Первый - использование предпросчитанных заранее значений и переменных и второе - это хороший алгоритм. Как в сортировке, например. Можно сортирвоать пузырьком и как ты его не оптимизируй, а будет все равно медленно, а можно сортировать шеллом, что будет в разы быстрее любого, даже самого навороченного пузырька. Но опять таки, палка о двух концах - при малом количестве значений, пузырек обгонит шелл. Так что правильные алгоритмы надо еще и правильно применять ))

Вот вы говорите, что занимаетесь геометрией и начали оптимизировать циклы. А вот у вас же наверное считаются там синусы и косинусы? А почему их заранее не посчитать?
Разработчик theFisherOnline - там, где клюёт
Разработчик Atom Fishing II - Первая 3D MMO про рыбалку
Разработчик Atom Fishing - Рыбалка на поплавок, донку, нахлыст, блесну в постъядерный период.
Аватара пользователя
Woolf
Адепт
 
Сообщения: 7179
Зарегистрирован: 02 мар 2009, 16:59

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение seaman 01 дек 2014, 16:30

Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

public class ArrayTest : MonoBehaviour
{
    private const int __ARRAY_LENGTH_TWO_X = 1000;
    private const int __ARRAY_LENGTH_TWO_Y = 1000;
    private const int __ARRAY_LENGTH_ONE = __ARRAY_LENGTH_TWO_X * __ARRAY_LENGTH_TWO_Y;

    private float __totalTimeOne = 0;
    private float __totalTimeOneTwo = 0;
    private float __totalTimeTwo = 0;

    public void Start()
    {
        __CallFewTests();
    }

    public void OnGUI()
    {
        if (__totalTimeOne > 0) GUILayout.Label("One-" + __totalTimeOne.ToString());
        if (__totalTimeOneTwo > 0) GUILayout.Label("OneTwo-" + __totalTimeOneTwo.ToString());
        if (__totalTimeTwo > 0) GUILayout.Label("Two-" + __totalTimeTwo.ToString());
    }

    private void __CallFewTests()
    {
        float timeBegin = Time.realtimeSinceStartup;
        for (int i = 0; i < 100; i++) __CalcArrayOne();
        __totalTimeOne = (Time.realtimeSinceStartup - timeBegin) * 1000;
        timeBegin = Time.realtimeSinceStartup;
        for (int i = 0; i < 100; i++) __CalcArrayOneTwo();
        __totalTimeOneTwo = (Time.realtimeSinceStartup - timeBegin) * 1000;
        timeBegin = Time.realtimeSinceStartup;
        for (int i = 0; i < 100; i++) __CalcArrayTwo();
        __totalTimeTwo = (Time.realtimeSinceStartup - timeBegin) * 1000;
    }

    private void __CalcArrayOne()
    {
        int[] a = new int[__ARRAY_LENGTH_ONE];
        for (int i = 0; i < __ARRAY_LENGTH_ONE; i++) a[i] = (int)Random.value;
    }
    private void __CalcArrayOneTwo()
    {
        int[] a = new int[__ARRAY_LENGTH_ONE];
        for (int i = 0; i < __ARRAY_LENGTH_TWO_X; i++)
        {
            for (int j = 0; j < __ARRAY_LENGTH_TWO_Y; j++) a[i * __ARRAY_LENGTH_TWO_Y + j] = (int)Random.value;
        }
    }
    private void __CalcArrayTwo()
    {
        int[,] a = new int[__ARRAY_LENGTH_TWO_X, __ARRAY_LENGTH_TWO_Y];
        for (int i = 0; i < __ARRAY_LENGTH_TWO_X; i++)
        {
            for (int j = 0; j < __ARRAY_LENGTH_TWO_Y; j++) a[i, j] = (int)Random.value;
        }
    }
}

В редакторе:
Изображение
Стендэлон:
Изображение
оптимизатор должен был пустой цикл убрать

В МОНО оптимизатор хреновый.
ЗЫ: Да, ТУТ есть еще несколько тестов.
seaman
Адепт
 
Сообщения: 8352
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение bwolf88 02 дек 2014, 20:44

Всеми любимая инкапсуляция:
Первые два теста - обычный монобех скрипт
Вторые два - статический экземпляр монобеха

Вывод: GetSet убивает скорость доступа почти в 3 раза (никогда не нравилась эта конструкция ;;) ). Чтобы ограничить доступ к изменению публичной переменной, проще использовать readonly.
По поводу использования ссылки на скрипт или статического экземпляра - противоречивые результаты, но в целом первые два показывают немного лучшие результаты, поэтому если объект долгоживущий, то лучше использовать его, если объекты с коротким сроком жизни то несомненно второй вариант.

Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

public class GetSetTest : MonoBehaviour {

    public static GetSetTest GST;

    int _var1 = 10;
    public int var1 { get { return _var1; }}

    public int var2 = 10;

    void Awake()
    {
        GST = this;
    }
}
 


Синтаксис:
Используется csharp
void GST1()
    {
        for (int i = 0; i < 10000000; i++)
        {
            gs = GST.var1;
        }
        //125 ms
    }

    void GST2()
    {
        for (int i = 0; i < 10000000; i++)
        {
            gs = GST.var2;
        }
        //48ms
    }

    void GST3()
    {
        for (int i = 0; i < 10000000; i++)
        {
            gs = GetSetTest.GST.var1;
        }
        //134ms
    }

    void GST4()
    {
        for (int i = 0; i < 10000000; i++)
        {
            gs = GetSetTest.GST.var2;
        }
        //53ms
    }
 
Сюда периодически чего нибудь выкладываю https://github.com/LuchunPen
Аватара пользователя
bwolf88
Адепт
 
Сообщения: 2184
Зарегистрирован: 30 апр 2014, 06:40
Skype: bwolf331

Re: Сравнительные тесты скорости расчетов типов данных

Сообщение bwolf88 03 дек 2014, 00:48

Целесообразность использования bool.

Тесты показывают, что скорость работы с битовым сдвигом примерно та же, что и с bool.
Поскольку bool b byte в NEt согласно справке занимают один байт памяти, то получаем 8-кратную экономию памяти на флагах, без потери скорости. Плюс, очень удобно задавать условия, используя нужную маску, вместо if (b1 && b2 && b5), просто написать соответствующее число со сдвигом, ну и за один раз можно больше флагов проверить :).

Эти тесты были нулевыми, немного переделал у себя и оказалось, что правильный битовый сдвиг работает даже быстрее нескольких && bool проверок :).

Синтаксис:
Используется csharp

 void BBT1()
    {
        for (int i = 0; i < 10000000; i++)
        {
            bTest = b1;
            bTest = b2;
            bTest = b3;
            bTest = b4;
            bTest = b5;
        }
        //126ms
    }

    void BBT2()
    {
        for (int i = 0; i < 10000000; i++)
        {
            bt2 = (1 & bt1);
            bt2 = (1 & bt1 >> 1);
            bt2 = (1 & bt1 >> 2);
            bt2 = (1 & bt1 >> 3);
            bt2 = (1 & bt1 >> 4);
        }
        //136ms - время больше потому что внутри другие вычисления
    }

    void BBT3()
    {
        for (int i = 0; i < 10000000; i++)
        {
            if ((b1 && b2) || (b3 && b4))
            {
                bt2 = bt1;
            }
        }
        //71ms
    }

    void BBT4()
    {
        for (int i = 0; i < 10000000; i++)
        {
            if ((128 & bt1 >> 1) == 122 || (64 & bt1) == 37)
            {
                bt2 = bt1;
            }
        }
        //71ms
    }

 
Сюда периодически чего нибудь выкладываю https://github.com/LuchunPen
Аватара пользователя
bwolf88
Адепт
 
Сообщения: 2184
Зарегистрирован: 30 апр 2014, 06:40
Skype: bwolf331

След.

Вернуться в Код

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2