Aleexeey
							
								Постоялец 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 «  : 23-01-2010 10:12 »   | 
								
								 | 
							  
							 
							Доброго всем времени суток! хотелось поговорить с вами по поводу  производительности методов на C++: 1) советы по повышению производительности из личного опыта; 2) наиболее продуктивные операции над переменными, и     возможные ошибки провоцирующие понижение эффективности; 3) наиболее эффективные способы использования функций (или классов),     от которых зависит вся производительность приложения (на C++); 4) ну и т. д. и т. п. если кто что-нибудь знает как "выжать" максимальную скорость и эффективность, отзовитесь!    спасибо всем за участие!  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Aleexeey
							
								Постоялец 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #1 : 23-01-2010 11:21 »   | 
								
								 | 
							  
							 
							Добавляю ссылки, относящиеся к этой теме: h**p://msdn.microsoft.com/ru-ru/library/ms235421.aspx -        инструкции по настройке оптимизации компилятора. h**p://blog.alno.name/2008/06/virtual-functions-in-cpp-and-performance -        проблема производительности виртуальных функций. h**p://msdn.microsoft.com/ru-ru/magazine/cc337887.aspx -        описание использование профилировщика (технология анализирования производительности приложений). 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 23-01-2010 16:21 от Алексей1153++ »
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Aleexeey
							
								Постоялец 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #2 : 23-01-2010 16:58 »   | 
								
								 | 
							  
							 
							h**p://www.gamedev.ru/code/faq/?id=3585                  самодельный замер производительности;
  h**p://www.realcoding.net/articles/tekhnika-optimizatsii-programm-fragment-23.html                  использование стандартных утилит: Intel VTune и AMD Code Analyst - мощные технологии оптимизации приложений;
  h**p://www.codenet.ru/progr/optimize/kk/                  пошаговое описание оптимизации приложений: выявления очень медленных функций (те, что грузят больше всех процессор),                  анализ количества вызовов, время выполнения, ..., а также анализ вплоть до каждой команды ассемблера. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 23-01-2010 17:08 от Алексей1153++ »
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #3 : 25-01-2010 08:28 »   | 
								
								 | 
							  
							 
							имхо это тема для статьи, а вот так взять и вывалить в одно 2 сообщение кучу знаний, это боюсь перебор. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #4 : 25-01-2010 18:07 »   | 
								
								 | 
							  
							 
							По теме. из личного опыта (мой хит парад): 1. не оптимальные алгоритмы 2. лишние копирования памяти (при работе с контейнерами есть ряд хитростей позволяющих уменьшить копирования) 3. выделение/высвобождение памяти 4. не верный выбор мьютекса 5. излишне длинные блокировки мои любимые ссылки (по параллелизму и lock-free): http://herbsutter.wordpress.com/http://software.intel.com/ru-ru/parallel/http://groups.google.com/group/lock-freePS: может общения оформить в вики? мой первый вклад Element c; c.a = 1; // первое копирование c.b = 2; // первое копирование ........................... std::vector<Element> Cont; Cont.push_back(c); // второе копирование
  иногда Element - это несколько килобайт немного оптимизируем: std::vector<Element> Cont; Cont.resize(Cont.size() + 1); Element & c = Cont.back(); c.a = 1; // одно копирование c.b = 2; // одно копирование
  просьба выбор контейнера не критиковать.  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #5 : 26-01-2010 05:31 »   | 
								
								 | 
							  
							 
							Хитрость номер 2. пускай есть некий map в котором естественно лежат некоторые данные, ключем для поиска является число (или строка    ) map по сути черно красное дерево в узлах которого лежит: typedef pair<key_type, mapped_type> value_type;
  если мы храним элементы, как обычно (по значению), то при поиске возникает ситуация, когда для того, чтобы проанализировать ключ из 4-х байт вынужден обновлять кэш линию, а иногда и не одну т.е. в кэш линию помещается не большое количество ключей или вообще не одного, из-за чего возникает потребность в обновлении кэш линий чаще чем нужно что бы убрать этот не приятный эффект, заменим  на тест: #include "stdafx.h" #include <iostream> #include <map> #include <fstream> #include <string> #include <typeinfo.h> #include <Windows.h>
  struct ElemType { 	char some_data_[128]; };
  typedef std::map<size_t, ElemType> StdCont; typedef std::map<size_t, long> OptiCont;
  size_t cMaxElem = 0x10000; size_t cMaxSearch = cMaxElem;
  template <typename T> void testMap(const std::string & testName) { 	T cont; 	T::mapped_type Elem; 	std::cout << testName << " fill count=" << cMaxElem 		<< " elem size="<< sizeof(T::value_type) 		<< " cont size="<< sizeof(T::value_type) * cMaxElem/1024 		<< std::endl; 	for (size_t i = 0; i != cMaxElem; ++i) 		cont.insert(cont.end(), std::make_pair(i,Elem));
  	std::cout << testName << " search=" << cMaxSearch << std::endl; 	size_t startTime = GetTickCount(); 	for (size_t i = 0; i != cMaxSearch; ++i) 	{ 		cont.find((rand() * rand())%cMaxElem); 	} 	size_t finishTime = GetTickCount(); 	size_t deltaTime = finishTime - startTime; 	std::cout << testName << " search done Time(ms)=" << (deltaTime) 		<< " ops=" << (1000.*cMaxElem/(deltaTime)) 		<< std::endl  << std::endl; }
  int main(int argc, char* argv[]) { 	if (argc > 1) 	{ 		cMaxElem = atoi(argv[1]); 		cMaxSearch = cMaxElem; 	}
  	if (argc > 2) 		cMaxSearch = atoi(argv[2]);
  	testMap<StdCont>("StdCont"); 	testMap<OptiCont>("OptiCont"); 	return 0; }
  результаты запусков с различными размерами элемента: C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=36 cont size=35156 StdCont search=1000000 StdCont search done Time(ms)=2297 ops=435350
  OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=2140 ops=467290
 
  C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=68 cont size=66406 StdCont search=1000000 StdCont search done Time(ms)=2500 ops=400000
  OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=1938 ops=515996
 
  C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=132 cont size=128906 StdCont search=1000000 StdCont search done Time(ms)=3032 ops=329815
  OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=2125 ops=470588
 
  C:\...s\My Documents\Visual Studio Projects\poli_examp\Release>poli_examp.exe 1000000 1000000 StdCont fill count=1000000 elem size=504 cont size=492187 StdCont search=1000000 StdCont search done Time(ms)=3860 ops=259067
  OptiCont fill count=1000000 elem size=8 cont size=7812 OptiCont search=1000000 OptiCont search done Time(ms)=2109 ops=474158
  при размере элемента в 500 байт, скорость поиска удвоилась  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Aleexeey
							
								Постоялец 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #6 : 26-01-2010 12:51 »   | 
								
								 | 
							  
							 
							Увеличить скорость можно также используя ассемблерные вставки: Т. к. обращение к любой переменной влечет обращению к памяти, а на ассемблере переменные хранятся в сверх быстрых регистрах процессора. вот пример: unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { 	unsigned int dstRB = (dst & 0x00ff00ff); 	unsigned int dstG = (dst & 0x0000ff00); 	unsigned int rb = (src & 0x00ff00ff) - dstRB; 	unsigned int g = (src & 0x0000ff00) - dstG;
  	rb *= alpha; 	g *= alpha; 	rb >>= 8; 	g >>= 8; 	rb += dstRB; 	g += dstG; 	rb &= 0x00ff00ff; 	g &= 0x0000ff00;
  	return (rb | g); }; теперь на ассемблере: unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { 	unsigned int Result = 0; 	__asm 	{ 		MOV EBX, dst 		AND EBX, 0xff00ff	// unsigned int dstRB = (dst & 0x00ff00ff); 		MOV EAX, src 		AND EAX, 0xff00ff 		SUB EAX, EBX		// unsigned int rb = (src & 0x00ff00ff) - dstRB; 		IMUL EAX, alpha		// rb *= alpha; 		SHR EAX, 0x8		// rb >>= 8; 		ADD EAX, EBX		// rb += dstRB; 		AND EAX, 0xff00ff	// rb &= 0x00ff00ff;
  		MOV EBX, dst 		AND EBX, 0xff00		// unsigned int dstG = (dst & 0x0000ff00); 		MOV ECX, src 		AND ECX, 0xff00 		SUB ECX, EBX		// unsigned int g = (src & 0x0000ff00) - dstG; 		IMUL ECX, alpha		// g *= alpha; 		SHR ECX, 0x8		// g >>= 8; 		ADD ECX, EBX		// g += dstG; 		AND ECX, 0xff00		// g &= 0x0000ff00;
  		OR EAX, ECX		// return (rb | g); 		MOV Result, EAX 	} 	return Result; };  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #7 : 26-01-2010 16:34 »   | 
								
								 | 
							  
							 
							Aleexeey, давай это отнесём к крайнему случаю кроме того где тест, доказывающий, что твой код быстрее чем код оптимизированный компилятором?    
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #8 : 26-01-2010 17:01 »   | 
								
								 | 
							  
							 
							Ассемблером делу не поможешь. Главный затык в производительности на современных процессорах - это даже не то, что какая-то формула считается целиком на регистрах, а то, что из-за непредсказуемых переходов сбрасывается конвейер, и у процессора случаются простои из-за неоптимального обмена данными между кэшами разных уровней и собственно оперативной памятью. А в данных вопросах заниматься оптимизацией можно только под конкретную железяку, зная в точности размер её кэшей и особенности работы конвейера.
  Поэтому нафиг - лучше довериться компилятору. Было время, когда ассемблерные вставки для CPU действительно имели смысл - когда CPU были простыми, а теория компиляции была менее совершенной. Сейчас в области приложений широкого профиля на универсальных машинах, по-моему, это уже из разряда легенд и мифологии.
  Вот, например, в коде на C для GPU (CUDA для видеокарт NVIDIA) борьба больше идёт за сокращение перемещений данных из обычной памяти в видепамять и обратно, нежели за оптимальность расчётных алгоритмов. Потому что время расчёта мизерно по сравнению со временем загрузки/выгрузки. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #9 : 26-01-2010 17:08 »   | 
								
								 | 
							  
							 
							эксперимент проведён    результаты в ms Blend time=14875
  Blend time=14719
  BlendAsm time=13891
  BlendAsm time=14296
  ИМХО прирост производительности в 7% не стоит уродования кода #include "stdafx.h" #include <string> #include <iostream> #include <windows.h>
  unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { 	unsigned int dstRB = (dst & 0x00ff00ff); 	unsigned int dstG = (dst & 0x0000ff00); 	unsigned int rb = (src & 0x00ff00ff) - dstRB; 	unsigned int g = (src & 0x0000ff00) - dstG;
  	rb *= alpha; 	g *= alpha; 	rb >>= 8; 	g >>= 8; 	rb += dstRB; 	g += dstG; 	rb &= 0x00ff00ff; 	g &= 0x0000ff00;
  	return (rb | g); };
  unsigned int BlendAsm(unsigned int dst, unsigned int src, unsigned int alpha) { 	unsigned int Result = 0; 	__asm 	{ 		MOV EBX, dst 		AND EBX, 0xff00ff	// unsigned int dstRB = (dst & 0x00ff00ff); 		MOV EAX, src 		AND EAX, 0xff00ff 		SUB EAX, EBX		// unsigned int rb = (src & 0x00ff00ff) - dstRB; 		IMUL EAX, alpha		// rb *= alpha; 		SHR EAX, 0x8		// rb >>= 8; 		ADD EAX, EBX		// rb += dstRB; 		AND EAX, 0xff00ff	// rb &= 0x00ff00ff;
  		MOV EBX, dst 		AND EBX, 0xff00		// unsigned int dstG = (dst & 0x0000ff00); 		MOV ECX, src 		AND ECX, 0xff00 		SUB ECX, EBX		// unsigned int g = (src & 0x0000ff00) - dstG; 		IMUL ECX, alpha		// g *= alpha; 		SHR ECX, 0x8		// g >>= 8; 		ADD ECX, EBX		// g += dstG; 		AND ECX, 0xff00		// g &= 0x0000ff00;
  		OR EAX, ECX		// return (rb | g); 		MOV Result, EAX 	} 	return Result; };
  size_t MaxCount = 1000000; typedef unsigned int (*BlendF)(unsigned int, unsigned int, unsigned int); void Test(BlendF f, const std::string & name) { 	size_t vect[1000] = { 0 }; 	size_t start = GetTickCount(); 	for(size_t i = 0; i != MaxCount; ++i) 	{ 		for(size_t j = 0; j != 1000; ++j) 			vect[j] = f(vect[j], i, j); 	} 	size_t finish = GetTickCount(); 	std::cout << name << " time=" << (finish - start) << std::endl << std::endl;
  	for(size_t j = 0; j != 1000; ++j) 		std::cerr << " " << vect[j] ; }
  int _tmain(int argc, _TCHAR* argv[]) { 	Test(Blend, "Blend"); 	Test(Blend, "Blend"); 	Test(BlendAsm, "BlendAsm"); 	Test(BlendAsm, "BlendAsm"); 	return 0; }
   
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #10 : 26-01-2010 17:22 »   | 
								
								 | 
							  
							 
							попытался эту хрень скомпилировать в GCC, удовольствие ниже среднего а если вспомнить том, что эту возможно придется переводить под MIPS с использованием хитрого компайлера от HP или куда по хлеще, становится совсем грустно    
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Aleexeey
							
								Постоялец 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #11 : 26-01-2010 18:24 »   | 
								
								 | 
							  
							 
							...Было время, когда ассемблерные вставки для CPU действительно имели смысл... ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)? впрочем неуместно будет здесь отстаивать эту точку зрения!  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #12 : 26-01-2010 18:38 »   | 
								
								 | 
							  
							 
							ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)? Кто эти загадочные "они"? О какой версии библиотеки от какого производителя и для какой платформы идёт речь?  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Finch
							
								Спокойный 
								Администратор
								
								 
								  Offline
								Пол:   
								
								Пролетал мимо
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #13 : 26-01-2010 22:46 »   | 
								
								 | 
							  
							 
							Aleexeey,  Вот код memset из glibc 2.10.1 /* Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc.    This file is part of the GNU C Library.
     The GNU C Library is free software; you can redistribute it and/or    modify it under the terms of the GNU Lesser General Public    License as published by the Free Software Foundation; either    version 2.1 of the License, or (at your option) any later version.
     The GNU C Library is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    Lesser General Public License for more details.
     You should have received a copy of the GNU Lesser General Public    License along with the GNU C Library; if not, write to the Free    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA    02111-1307 USA.  */
  #include <string.h> #include <memcopy.h>
  #undef memset
  void * memset (dstpp, c, len)      void *dstpp;      int c;      size_t len; {   long int dstp = (long int) dstpp;
    if (len >= 8)     {       size_t xlen;       op_t cccc;
        cccc = (unsigned char) c;       cccc |= cccc << 8;       cccc |= cccc << 16;       if (OPSIZ > 4) 	/* Do the shift in two steps to avoid warning if long has 32 bits.  */ 	cccc |= (cccc << 16) << 16;
        /* There are at least some bytes to set. 	 No need to test for LEN == 0 in this alignment loop.  */       while (dstp % OPSIZ != 0) 	{ 	  ((byte *) dstp)[0] = c; 	  dstp += 1; 	  len -= 1; 	}
        /* Write 8 `op_t' per iteration until less than 8 `op_t' remain.  */       xlen = len / (OPSIZ * 8);       while (xlen > 0) 	{ 	  ((op_t *) dstp)[0] = cccc; 	  ((op_t *) dstp)[1] = cccc; 	  ((op_t *) dstp)[2] = cccc; 	  ((op_t *) dstp)[3] = cccc; 	  ((op_t *) dstp)[4] = cccc; 	  ((op_t *) dstp)[5] = cccc; 	  ((op_t *) dstp)[6] = cccc; 	  ((op_t *) dstp)[7] = cccc; 	  dstp += 8 * OPSIZ; 	  xlen -= 1; 	}       len %= OPSIZ * 8;
        /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain.  */       xlen = len / OPSIZ;       while (xlen > 0) 	{ 	  ((op_t *) dstp)[0] = cccc; 	  dstp += OPSIZ; 	  xlen -= 1; 	}       len %= OPSIZ;     }
    /* Write the last few bytes.  */   while (len > 0)     {       ((byte *) dstp)[0] = c;       dstp += 1;       len -= 1;     }
    return dstpp; } libc_hidden_builtin_def (memset)
  Не вижу, где тут ассемблер.  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Не будите спашяго дракона.              Джаффар (Коша)  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #14 : 27-01-2010 07:23 »   | 
								
								 | 
							  
							 
							...Было время, когда ассемблерные вставки для CPU действительно имели смысл... ну почему тогда функции strcpy, memset, ... оптимизировали Inline Assembler (встроенным ассемблером)? впрочем неуместно будет здесь отстаивать эту точку зрения! ну что же давай начнём сначала. понятно что можно писать на асме, но в таком случае причем тут C++ стоимость поддержки решения сильно возрастает, приходится поддерживать код для кучу компиляторов разом (это мой случай) я совершенно не против асма когда это действительно необходимо что касается memcpy то эта функция максимально приближена по своей сути к железу, а не к прикладной логике, к тому же она может быть реализована на асме всего парой строк. и как справедливо заметил Finch не всегда она реализована на asm. есть еще один не приятный момент во вставке asm, компилятор долго выстраивал команды, прореживал их nop`ами менял операции местами, что бы максимально наполнить конвейеры процессора, а тут ты весь такой на белом коне и в шляпе, одну маленькую инструкцию встраиваешь она же "быстрая", при этом разрушаешь порядок команд и часть конвейеров процессора пару тактов отрабатывают в холостую. повторил тест на работе в студии по младше но зато не Express (в которой нет кое-каких опций сборки) Blend time=16360 Blend time=15109
  BlendAsm time=18265 BlendAsm time=19625
  чувствуешь разницу? asm проигрывает. это то что сгеренерировал сам компилятор: unsigned int Blend(unsigned int dst, unsigned int src, unsigned int alpha) { 	unsigned int dstRB = (dst & 0x00ff00ff); 00401000  mov         eax,dword ptr [esp+4]  	unsigned int dstG = (dst & 0x0000ff00); 	unsigned int rb = (src & 0x00ff00ff) - dstRB; 00401004  mov         ecx,dword ptr [esp+8]  00401008  mov         edx,eax  0040100A  and         eax,0FF00h  0040100F  push        esi   00401010  mov         esi,eax  00401012  mov         eax,ecx  00401014  and         eax,0FF00FFh  	unsigned int g = (src & 0x0000ff00) - dstG; 00401019  and         ecx,0FF00h  0040101F  sub         ecx,esi  00401021  push        edi  
  	rb *= alpha; 00401022  mov         edi,dword ptr [esp+14h]  00401026  and         edx,0FF00FFh  	g *= alpha; 0040102C  imul        ecx,edi  0040102F  sub         eax,edx  00401031  imul        eax,edi  	rb >>= 8; 00401034  shr         eax,8  	g >>= 8; 00401037  shr         ecx,8  	rb += dstRB; 0040103A  add         eax,edx  	g += dstG; 0040103C  add         ecx,esi  	rb &= 0x00ff00ff; 0040103E  and         eax,0FF00FFh  	g &= 0x0000ff00; 00401043  and         ecx,0FF00h  00401049  pop         edi  
  	return (rb | g); 0040104A  or          eax,ecx  0040104C  pop         esi   }; 0040104D  ret   
  при желании можно повторить тест используя gcc и icc опции: -mtune=pentium4 -O2 gcc (тесты выполнялись на железяке отличное от предыдущих и в RHEL5) Blend time=10837 Blend time=10821
  BlendAsm time=11623 BlendAsm time=11580
  icc(подозреваю что icc переколбасил код) Blend time=6476 Blend time=6480
  BlendAsm time=6391 BlendAsm time=6370
  проверяем BlandAsm cгенерированный icc Dump of assembler code for function _Z8BlendAsmjjj:     0x080494fa <BlendAsm(unsigned int, unsigned int, unsigned int)+0>:      push   %edi     0x080494fb <BlendAsm(unsigned int, unsigned int, unsigned int)+1>:      push   %ebp     0x080494fc <BlendAsm(unsigned int, unsigned int, unsigned int)+2>:      push   %ebx     0x080494fd <BlendAsm(unsigned int, unsigned int, unsigned int)+3>:      mov    0x10(%esp),%edx     0x08049501 <BlendAsm(unsigned int, unsigned int, unsigned int)+7>:      mov    0x14(%esp),%ebp     0x08049505 <BlendAsm(unsigned int, unsigned int, unsigned int)+11>:     mov    0x18(%esp),%edi     0x08049509 <BlendAsm(unsigned int, unsigned int, unsigned int)+15>:     mov    %edx,%ebx     0x0804950b <BlendAsm(unsigned int, unsigned int, unsigned int)+17>:     and    $0xff00ff,%ebx     0x08049511 <BlendAsm(unsigned int, unsigned int, unsigned int)+23>:     mov    %ebp,%eax     0x08049513 <BlendAsm(unsigned int, unsigned int, unsigned int)+25>:     and    $0xff00ff,%eax     0x08049518 <BlendAsm(unsigned int, unsigned int, unsigned int)+30>:     sub    %ebx,%eax     0x0804951a <BlendAsm(unsigned int, unsigned int, unsigned int)+32>:     imul   %edx,%eax     0x0804951d <BlendAsm(unsigned int, unsigned int, unsigned int)+35>:     shr    $0x8,%eax     0x08049520 <BlendAsm(unsigned int, unsigned int, unsigned int)+38>:     add    %ebx,%eax     0x08049522 <BlendAsm(unsigned int, unsigned int, unsigned int)+40>:     and    $0xff00ff,%eax     0x08049527 <BlendAsm(unsigned int, unsigned int, unsigned int)+45>:     mov    %edx,%ebx     0x08049529 <BlendAsm(unsigned int, unsigned int, unsigned int)+47>:     and    $0xff00,%ebx     0x0804952f <BlendAsm(unsigned int, unsigned int, unsigned int)+53>:     mov    %ebp,%ecx     0x08049531 <BlendAsm(unsigned int, unsigned int, unsigned int)+55>:     and    $0xff00,%ecx     0x08049537 <BlendAsm(unsigned int, unsigned int, unsigned int)+61>:     sub    %ebx,%ecx     0x08049539 <BlendAsm(unsigned int, unsigned int, unsigned int)+63>:     imul   %edi,%ecx     0x0804953c <BlendAsm(unsigned int, unsigned int, unsigned int)+66>:     shr    $0x8,%ecx     0x0804953f <BlendAsm(unsigned int, unsigned int, unsigned int)+69>:     add    %ebx,%ecx     0x08049541 <BlendAsm(unsigned int, unsigned int, unsigned int)+71>:     and    $0xff00,%ecx     0x08049547 <BlendAsm(unsigned int, unsigned int, unsigned int)+77>:     or     %ecx,%eax     0x08049549 <BlendAsm(unsigned int, unsigned int, unsigned int)+79>:     mov    %eax,%edx     0x0804954b <BlendAsm(unsigned int, unsigned int, unsigned int)+81>:     mov    %edx,%eax     0x0804954d <BlendAsm(unsigned int, unsigned int, unsigned int)+83>:     pop    %ebx     0x0804954e <BlendAsm(unsigned int, unsigned int, unsigned int)+84>:     pop    %ebp     0x0804954f <BlendAsm(unsigned int, unsigned int, unsigned int)+85>:     pop    %edi     0x08049550 <BlendAsm(unsigned int, unsigned int, unsigned int)+86>:     ret         0x08049551 <BlendAsm(unsigned int, unsigned int, unsigned int)+87>:     nop     End of assembler dump.
  и наблюдаем интересную картину - icc решил, что мы не слишком сильны в кодировании на asm. именно по этому я полагаюсь на компилятор  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Aleexeey
							
								Постоялец 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #15 : 27-01-2010 12:56 »   | 
								
								 | 
							  
							 
							Полностью с вами согласен! Оптимизация программного кода компилятором - наилучший вариант, ЕСЛИ ты не лучше компилятора! Finch не догадывался, что на старинке сижу, буду менять! LogRus! я что-то не пойму! как компилятор ICC добился такой скорости? опции: -mtune=pentium4 -O2 прежние замеры были на той же машине?  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #16 : 27-01-2010 13:52 »   | 
								
								 | 
							  
							 
							первый тест - домашний AMD Athlon XP 2500+ - VS Express 2008 - O2 + Blended второй тест - рабочий P4 2400 - VS Enterprise 2003 - O2 + Pentium4 третий + четвёртый - рабочий 2xZeon - GCC/ICC - O2 + Pentium4 Полностью с вами согласен! Оптимизация программного кода компилятором - наилучший вариант, ЕСЛИ ты не лучше компилятора!
  попервых, как видишь ты оказался не лучше   во вторых, ранняя оптимизация корень всех зол в третьих, пиши на ассемблере    зачем тогда вообще С++ и тема в этом разделе тоже не нужна. в четвёртых, иногда действительно без ASM не обойтись, но уж точно не в ситуации с калькуляцией пары 32-х битных чисел. а то получается, такая фигня, народ сидит, тратит годы на изучение: архитектур, особенностей работы и т.д. и т.п. Пишут компиляторы, оптимизируют базовые библиотеки. Понимая, что от качества конкретно их работы, зависит скорость кучи ПО. А тут я или еще кто, приходит весь в белом и с порога заявляет: "Компилятор ваш фуфло, я круче могу" Можешь? Пиши на асме и студия тебе не нужна. Коллеги давайте вернёмся к хитростям в C++, а не упражнениям на ASM и так уже Холивар пошел.  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							sss
							
								Специалист 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #17 : 28-01-2010 08:32 »   | 
								
								 | 
							  
							 
							LogRus,  не в тему конечно, но почему деревья черно-красные а не красно-черные?  У меня MIT-овский курс "Алгоритмы" с  красно-черными деревьями? До этого вы меня поправляли и вот опять... Почему?
  P.S.: Ещё не забывайте про кодовое слово register в C++. Можно 7% производительность добытую asm-ом опрокинуть... 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 28-01-2010 08:42 от sss »
								 | 
								
									 
									Записан
								 | 
							  
							 
							 while (8==8)  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							RXL
							
						 | 
						
							
								  | 
								
									
									 « Ответ #18 : 28-01-2010 08:50 »   | 
								
								 | 
							  
							 
							sss, поддерживаю: красно-черные (red black tree, rbtree). Хотя, в общем-то, смысл особо не меняется. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							sss
							
								Специалист 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #19 : 28-01-2010 09:25 »   | 
								
								 | 
							  
							 
							Ну я только никого не хочу обидеть.... Я вон тоже register кодовым а не ключевым словом обозвал. Просто вдруг где нибудь в толмутах так дают... 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							 while (8==8)  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #20 : 28-01-2010 11:39 »   | 
								
								 | 
							  
							 
							sss, а хакер его знает, лично мне до лампочки    
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	| 
		
		
	 | 
	| 
		
		
	 | 
	 |