Solved

multithreading .net vc++ windows form application

Posted on 2009-05-14
32
392 Views
Last Modified: 2013-11-08
I have several tabs in my main form. at form load, each one of the tabs get filed by calling separate functions for what goes in each tab:

Form1_Load( )
 tab1();
tab2();
 ....
 tab7();

the problem right now is that since each tab is getting loaded at form load, the program takes good 15-20 secs to start. i was wondering if there is a way to split this task in multiple threads or multiple processes  to get it done faster?
I am using windows forms application, vc++ and VS2008
0
Comment
Question by:funcoding
  • 20
  • 10
  • 2
32 Comments
 
LVL 1

Author Comment

by:funcoding
Comment Utility
forgot to mention that the application takes all this long to load up and then when each tab is clicked, it takes another few seconds for the tools on that tab to appear, very slow. Mainly because i have for loops at each tab load to generate tools in multiple rows and columns. but once i have clicked on one tab and all the tools have loaded, i can go to another tab and come back and it doesn't any time for the tools to come up. So i guess the overhead is only at the first time the form loads and also when a tab is clicked on for the first time.
0
 
LVL 16

Expert Comment

by:HooKooDooKu
Comment Utility
Rule #1 about Multithreading, it doesn't make things run faster.  It just makes an application more responsive.  As an example, if you load all the tabs inside of a thread, your application will respond the things like mouse clicks and form resize events because the main processing thread isn't tied up in the logic loading tabs.

Now if something else is going on, like say the application is displaying a splash screen or prompting the user for a password, while the application does those things, it's not going to be using much processor power.  That is when it's a good idea to use multithreading.

So unless the current application has some dead time in it, the only thing you will accomplish running in multithreading is all the tabs will load at the same time, but each tab will load slower because they are all sharing the same CPU and will still take a total of about 15 seconds.

The bigger question is what is taking so long to load the tabs?  if the answer is that it"s waiting to retrieve information from a database located on another computer, then multithreading might make things faster.  The reason would be that Tab1 might be able to do some of the work running calculations to layout the tab, while Tab2 is waiting on the DB server to respond.  That's an example where multithreading speeds things up, because while one thread is "stuck" waiting for something to happen, other threads can use that wait time to do something.

But if all the processing is on your machine and there isn't dead time, multithreading won't help.
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
thanks for the clarification. at the moement, I am not trying to retrieve info from server, this is all from my pc. Part of the problem is that i am using older code for generating the tabs. Below is code for just one tab.



private: System::Void Filltab()

			{

				// Fill in the following variables to customize the table

				int NumCols = 8;

				int NumRows = 10;

				int ColWidth[] = {130, 50, 150, 50, 175, 125, 100, 80};

				

				int i, Spacing;

				int TableX = 30;  // distance between table and left of window

				int TableY = 60;  // distance between table and top of window

				int TableHeight = this->tabPage2->Height - 100;  //Fill in tabPage

				int TitleX = 30;  // distance between left column title and left of window

				int TitleY = 40;  // distance between column titles and top of window

				int RowHeight = 25;

				StringCollection^ ColumnTitles = gcnew StringCollection;

				// Fill in the definition of controls for the table

				System::Windows::Forms::Label^ Title;

				System::Windows::Forms::Button^ button1;

				System::Windows::Forms::Button^ button2;

				System::Windows::Forms::CheckBox^ checkbox1;

				System::Windows::Forms::ComboBox^ combobox2;

				System::Windows::Forms::ComboBox^combobox3;

				System::Windows::Forms::ComboBox^ combobox4;

				System::Windows::Forms::TextBox^ textbox1;

				System::Windows::Forms::TableLayoutPanel^  table1;
 

				ColumnTitles->AddRange( myArr );

				tabletab = gcnew System::Windows::Forms::TableLayoutPanel();

				tabletab->Location = System::Drawing::Point(TableX, TableY);

				tabletab->ColumnCount = NumCols;

				tabletab->RowCount = NumRows;

				tabletab->AutoScroll = true;
 

				this->SuspendLayout();
 

				// Create column titles and format widths of table columns

				for ( i=0; i<NumCols; i++  )

				{

					Title = gcnew System::Windows::Forms::Label();

					Title->Text = ColumnTitles[i];

					Title->AutoSize = true;

					if ( i == 0 )

					{

						Title->Location = System::Drawing::Point(TitleX+10, TitleY);  // The 10 is added to line it up with the text on the buttons directly below it

						Spacing = ColWidth[i];

					}

					else

					{

						Title->Location = System::Drawing::Point(TitleX + Spacing, TitleY);

						Spacing += ColWidth[i];

					}

					tabletab->ColumnStyles->Add(gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, (float) ColWidth[i]));

					this->tabPage7->Controls->Add(Title);  // Fill in correct tabPage number

				}
 

				// make sure that the table doesn't over run the size of the tab control

				if ( Spacing > (tabControl1->Width - 100) )

				{

					Spacing = tabControl1->Width - 100;

				}

				tabletab->Size = System::Drawing::Size(Spacing + 50, TableHeight);
 

				// Fill in code for each control in the table

				for ( i=0; i<NumRows; i++  )

				{

					tabletab->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Absolute, (float) RowHeight)));
 

					 button1 = gcnew System::Windows::Forms::Button();

					if ( i < 9 )

					{

						 button1->Text = "text" + (i+1).ToString();

					}

					else

					{

						 button1->Text = "text" + (i+1).ToString();

					}

					 button1->AutoSize = true;

					 button1->FlatAppearance->BorderSize = 0;

					 button1->FlatStyle = System::Windows::Forms::FlatStyle::Flat;

					 button1->TextAlign = System::Drawing::ContentAlignment::TopLeft;

					

					 button2 = gcnew System::Windows::Forms::Button();

					 button2->Text = "J" + (i+1).ToString();

					 button2->AutoSize = true;

					 button2->FlatAppearance->BorderSize = 0;

					 button2->FlatStyle = System::Windows::Forms::FlatStyle::Flat;

					 button2->TextAlign = System::Drawing::ContentAlignment::TopLeft;

					

					Textbox1 = gcnew System::Windows::Forms::TextBox();

					Textbox1->Text = "";

					Textbox1->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					tableResOut->Controls->Add(TextControl, 2, i);
 

					// Enable CheckBox

					checkbox1 = gcnew System::Windows::Forms::CheckBox();

					checkbox1->Checked = false;

					
 

					// Drop Down

					combobox2= gcnew System::Windows::Forms::ComboBox();

					combobox2->DropDownStyle = ComboBoxStyle::DropDownList;

					combobox2->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					combobox2->Items->Add("324-178800");

					combobox2->Items->Add("324-178801");

					combobox2->Items->Add("324-178802");

					combobox2->Items->Add("324-178803");

					combobox2->Items->Add("324-178804");

					tabletab->Controls->Add(combobox2, 4, i);
 

					// Layout Name

					combobox3 = gcnew System::Windows::Forms::ComboBox();

					combobox3->DropDownStyle = ComboBoxStyle::DropDownList;

					combobox3->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					combobox3->Items->AddRange( this->DefaultLayouts );

					tabletab->Controls->Add(combobox3, 5, i);
 

					// Instrument Type

					combobox4 = gcnew System::Windows::Forms::ComboBox();

					combobox4->DropDownStyle = ComboBoxStyle::DropDownList;

					combobox4->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					combobox4->Items->Add("NumericInput");

					combobox4->Items->Add("Slider");

					combobox4->Items->Add("Knob");

					combobox4->Text = "NumericInput";

					tabletab->Controls->Add(combobox4, 6, i);
 

					Textbox1 = gcnew System::Windows::Forms::TextBox();

					Textbox1->Text = "";

					tabletab->Controls->Add(Textbox1, 7, i);

				}
 

				// Fill in correct tabPage and Index

				this->tabPage7->Controls->Add(tabletab);

				Table7Index = this->tabPage7->Controls->Count-1;

				this->ResumeLayout(false);

			}

Open in new window

0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
this much is just for one tab and then there are about 7 of them. It takes a good few seconds for the main window to come up and as i said each tab takes its own time afterwards
0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
The "golden rule of optimization" is to use a profiler to measure how much time is spent in the different parts of your code.
The only profiler I have had good experiences with is shiny:

http://sourceforge.net/docman/?group_id=208504

It's a bit of pain that it does not work "out of the box". I had to compile it into a separate library (in the same way as you would create any other C++ library). A quick and dirty approach - if you want to play with it - would be to add all Shiny source files directly to your project.  However, after that, it is a great tool.

To use it, you should include Shiny.h in your main.cpp file (or similar), and at the end of the main function put the lines

PROFILER_UPDATE()
PROFILER_OUTPUT()

Then in your code, to know how much time is spent in a particular section, you can surround that section with PROFILE_BEGIN( name ) and PROFILE_END macros.

PROFILE_BEGIN ( fillDropDown )
combobox2= gcnew System::Windows::Forms::ComboBox();
combobox2->DropDownStyle = ComboBoxStyle::DropDownList;
// etc, etc
PROFILE_END ()

The measured times for the different sections will be printed when the program exits the main function.
I have tried commercial profiler tools which have a GUI, but they would crash or give >very< inaccurate results.
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
thanks for the suggestion maartennieber. I will check it out, would be useful for other projects also.
Any suggestions for making for loops of all the tabs like the one i have posted earlier any better/faster?
When i posted this question, i was thinking the program download accelerator, that splits the file to be downloaded. Is there not a way to do something like that here to speed the startup of form faster?
0
 
LVL 16

Expert Comment

by:HooKooDooKu
Comment Utility
Well, I must say that a brief overview of the tab loading logic doesn't show any obvious places where things are slowing down.  But it is obviously doing a lot of updating the user interface.  A lot of your time MIGHT simply be in refreshing the window over and over again.  If that is indeed the issue, then a typical solution is to hide the window while you make a bunch of updates, and then show the window once all the updates have been made.  That way the window and the controls only get drawn once.
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
Is there any other way of populating the tools in each row that may speed up the load process?
I have static texts, drop down menus, and checkboxes. I think a total of about 8, 9 of the toolboxes in each row and about 20 rows on each tab. What would be an efficient way of populating such tools on project startup?
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
I guess i would have to start a new question and maybe ask my question in a better way...
0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
I would like to help you, but in my experience, it pays to do things systematically, which means in this case: use a profiler to find out where the application is spending too much time.
Just guessing what needs to be changed will likely produce sub-optimal results and will probably cost you more time than learning how to use the profiler.

A note on the Shiny profiler: if you decide to put the Shiny code in a library, then create a DLL and not a static lib. A Shiny DLL will be shared by all libraries in your solution (whereas a static lib will not), and this will allow you to obtain profiling data from different libraries in a single report.
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
maartennieber, I am trying to build the shiny project. the project itself has Shiny, Recursion and Simple in it. I edited Shiny properties under Project Deafults->Configuration type, i changed that to Dynamic library. Now when i build the project it only generates the dll and not the lib or header with it for me to add to my project. what do i need to do for the project to export symbols also? and if you could comment on how i would add it to my project also. Thanks
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
Following is the output of the profiler:
flat profile                               hits       self time      total time
<root>                                      1.0     11 s    67%     27 s   167%
GUI_IP::Form1::Form1_Load                   1.0     20 ms    0%     16 s   100%
GUI_IP::Form1::tab1                      1.0      3 s    19%      3 s    19%
GUI_IP::Form1::tab2                      1.0    604 ms    4%    604 ms    4%
GUI_IP::Form1::tab3                   1.0    258 ms    2%    258 ms    2%
GUI_IP::Form1::tab4                   1.0      4 s    23%      4 s    23%
GUI_IP::Form1::tab5                    1.0    643 ms    4%    643 ms    4%
GUI_IP::Form1::tab6                   1.0      4 s    24%      4 s    24%
GUI_IP::Form1::tab7                    1.0      4 s    25%      4 s    25%

call tree                                  hits       self time      total time
<root>                                      1.0     11 s    67%     27 s   167%
  GUI_IP::Form1::Form1_Load                 1.0     20 ms    0%     16 s   100%
    GUI_IP::Form1::tab1                  1.0      3 s    19%      3 s    19%
    GUI_IP::Form1::tab2                  1.0    604 ms    4%    604 ms    4%
    GUI_IP::Form1::tab3               1.0    258 ms    2%    258 ms    2%
    GUI_IP::Form1::tab4               1.0      4 s    23%      4 s    23%
    GUI_IP::Form1::tab5                1.0    643 ms    4%    643 ms    4%
    GUI_IP::Form1::tab6               1.0      4 s    24%      4 s    24%
    GUI_IP::Form1::tab7                1.0      4 s    25%      4 s    25%
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
I forgot to mention that i didn't use the way you specified for the profiler call. you had said profiler_begin(func_name). Instead, I called PROFILER_FUNC() at the beginning of the each function
I was looking at the time each one of these took and it makes sense for diff times for each tab because i have diff number of rows and elements in each tab and the time shown by profiler is proportional to what i have in each tab
0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
Great, this already tells us that it is not a single tab that acts as the bottleneck.

I would now suggest to select the simplest one of the slow functions (either tab1, tab4, tab6 or tab7, whichever is simplest), and try to detail the profile by creating profiled sections using PROFILE_BEGIN (nameOfSubSection) and PROFILE_END().

Hopefully there is a bottleneck somewhere within this tab's code that we can eliminate. If you post the code for the selected tab function, I can give some hints as to which subsections to create.
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
alright, so i split tab1 function into 4 sub-groups and i got the following time:

call tree                                  hits       self time      total time
<root>                                      1.0     35 s   205%     52 s   305%
  GUI_IP::Form1::Form1_Load                 1.0     14 s    80%     17 s   100%
    first                              1.0    174 us    0%    174 us    0%
    second                              1.0    258 us    0%    258 us    0%
    third                               1.0      3 s    20%      3 s    20%
    fourth                              1.0    256 us    0%    256 us    0%

as you can see, the third group is taking the most time.  I *think* the statement:
Title = gcnew System::Windows::Forms::Label();
input1 = gcnew System::Windows::Forms::Button();
input2 = gcnew System::Windows::Forms::CheckBox();      
input3 = gcnew System::Windows::Forms::ComboBox();

and so on until input6 are causing the most delay because of the gcnew. what would you recommend to optimize this? Thanks

				PROFILE_BEGIN(first);

				int i, Spacing;

				int TableX = 30;

				int TableY = 60;

				int TableHeight = this->tabPage1->Height - 100;

				int NumCols = 6;

				ADC_NumCols=NumCols;

				int NumRows = 47;

				ADC_NumRows=NumRows;

				int TitleX = 30;

				int TitleY = 40;

				int ColWidth[] = {150, 50, 200, 150, 100, 100};

				int RowHeight = 25;

				StringCollection^ ColumnTitles = gcnew StringCollection;

				array<String^>^myArr = {"A", "B", "C", "D", "E", "F"};

				System::Windows::Forms::Label^ Title;

				System::Windows::Forms::Button^ input1;

				System::Windows::Forms::CheckBox^ input2;

				System::Windows::Forms::ComboBox^ input3;

				System::Windows::Forms::ComboBox^ input4;

				System::Windows::Forms::ComboBox^ input5;

				System::Windows::Forms::TextBox^ input6;

				System::Windows::Forms::TableLayoutPanel^  table;

				PROFILE_END();
 

				

				PROFILE_BEGIN(second_ADC);

				ColumnTitles->AddRange( myArr );

				table = gcnew System::Windows::Forms::TableLayoutPanel();

				table->Location = System::Drawing::Point(TableX, TableY);

				table->ColumnCount = NumCols;

				table->RowCount = NumRows;

				table->AutoScroll = true;

				PROFILE_END();
 
 
 

				PROFILE_BEGIN(third_ADC);

				this->SuspendLayout();
 

				// Create column titles and format widths of table columns

				for ( i=0; i<NumCols; i++  )

				{

					Title = gcnew System::Windows::Forms::Label();

					Title->Text = ColumnTitles[i];

					Title->AutoSize = true;

					if ( i == 0 )

					{

						Title->Location = System::Drawing::Point(TitleX+10, TitleY);

						Spacing = ColWidth[i];

					}

					else

					{

						Title->Location = System::Drawing::Point(TitleX + Spacing, TitleY);

						Spacing += ColWidth[i];

					}

					table->ColumnStyles->Add(gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, (float) ColWidth[i]));

					this->tabPage1->Controls->Add(Title);

				}

				table->Size = System::Drawing::Size(Spacing + 50, TableHeight);
 

				for ( i=0; i<NumRows; i++  )

				{

					table->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Absolute, (float) RowHeight)));
 

					

					input1 = gcnew System::Windows::Forms::Button();

					if ( i < 9 )

					{

						input1->Text = "inupt_0" + (i+1).ToString();

					}

					else if ( i < 32 )

					{

						input1->Text = "inupt_" + (i+1).ToString();

					}

					else if ( i < 41 )

					{

						input1->Text = "inupt1_0" + (i-31).ToString();

					}

					else

					{

						input1->Text = "inupt1_" + (i-31).ToString();

					}

					input1->AutoSize = true;

					input1->FlatAppearance->BorderSize = 0;

					input1->FlatStyle = System::Windows::Forms::FlatStyle::Flat;

					input1->TextAlign = System::Drawing::ContentAlignment::TopLeft;

					

					table->Controls->Add(input1, 0, i);
 

					input2 = gcnew System::Windows::Forms::CheckBox();

					input2->Checked = false;

					table->Controls->Add(input2, 1, i);
 

					input3 = gcnew System::Windows::Forms::ComboBox();

					input3->DropDownStyle = ComboBoxStyle::DropDownList;

					input3->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					input3->Items->Add("a");

					input3->Items->Add("b");

					input3->Items->Add("c");

					input3->Items->Add("d");

					input3->Items->Add("e");

					input3->Items->Add("f");

					input3->Items->Add("g");

					input3->Items->Add("h");

					input3->Items->Add("i");

					table->Controls->Add(input3, 2, i);
 

					input4 = gcnew System::Windows::Forms::ComboBox();

					input4->DropDownStyle = ComboBoxStyle::DropDownList;

					input4->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					input4->Items->AddRange( this->DefaultLayouts );

					table->Controls->Add(input4, 3, i);
 

					input5 = gcnew System::Windows::Forms::ComboBox();

					input5->DropDownStyle = ComboBoxStyle::DropDownList;

					input5->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					input5->Items->Add("1");

					input5->Items->Add("2");

					table->Controls->Add(input5, 4, i);
 

					input6 = gcnew System::Windows::Forms::TextBox();

					input6->Text = "";

					table->Controls->Add(input6, 5, i);

				}

				PROFILE_END();
 

				PROFILE_BEGIN(fourth_ADC);

				this->tabPage1->Controls->Add(table);

				Table1Index = this->tabPage1->Controls->Count-1;

				this->ResumeLayout(false);

				PROFILE_END();

Open in new window

0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
Is there a way to preallocate all those buttons and check boxes etc.. ?
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Author Comment

by:funcoding
Comment Utility
Is there a way to preallocate all those buttons and check boxes etc.. ?
0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
Just to check that I'm following how you proceeded:

- did you remove the Shiny macro calls you were previously using? That's okay in itself, I just wondered why the GUI_IP::Form1::tab1 disappeared in the Shiny output.

- how come the Shiny output contains the label 'third', wheras in your code the section is called 'third_ADC'? (did you edit the shiny output?)

Since your third section (which takes up all the processing time) is still quite big, I would proceed by making yet more sub-sections within the third section. We should try to pinpoint the bottlenecks, we have not yet done that.

About your hypothesis that the time is spent in gcnew: that's possible, but before trying to optimize these calls you should verify your hypothesis by placing Shiny macro calls around the calls to these constructors. Again, I would not choose this option right now, but instead go for the option mentioned above: splitting the third group into smaller sections.


0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
yea, i realized that the two were different as soon as i posted it here, sorry about the confusion. I had taken the GUI IP line out of the shiny output while posting it on here. I have tried to stay consistent with last time. So i kept the first, second and fourth call where they were. The third one is the one that i split up further. Basically i called the profiler before almost every gcnew call. And following is the output:

call tree                                  hits       self time      total time
<root>                                      1.0     15 s    72%     36 s   172%
  GUI_IP::Form1::Form1_Load                 1.0     17 s    84%     21 s   100%
    first                                   1.0    394 us    0%    394 us    0%
    second                                  1.0     49 us    0%     49 us    0%
    third                                   1.0     34 us    0%    552 us    0%
      third_a                               6.0    113 us    0%    113 us    0%
      third_b                               6.0    404 us    0%    404 us    0%
    third_c                                 1.0    725 us    0%      4 s    17%
      third_d                              47.0    825 ms    4%    825 ms    4%
      third_e                              47.0    557 ms    3%    557 ms    3%
      third_f                              47.0    560 ms    3%    560 ms    3%
      third_g                              47.0    534 ms    3%    534 ms    3%
      third_h                              47.0      1 s     5%      1 s     5%
    fourth                                  1.0    250 us    0%    250 us    0%

"third" is a wrap around third_a and third_b. third_c is a wrap around the big for loop that has the rest of the third_  within it.  So as it appears, this tab itself is taking around 6secs out of the 21 total the form_load is taking.
				PROFILE_BEGIN(first);

				int i, Spacing;

				int TableX = 30;

				int TableY = 60;

				int TableHeight = this->tabPage1->Height - 100;

				int NumCols = 6;

				ADC_NumCols=NumCols;

				int NumRows = 47;

				ADC_NumRows=NumRows;

				int TitleX = 30;

				int TitleY = 40;

				int ColWidth[] = {150, 50, 200, 150, 100, 100};

				int RowHeight = 25;

				StringCollection^ ColumnTitles = gcnew StringCollection;

				array<String^>^myArr = {"A", "B", "C", "D", "E", "F"};

				System::Windows::Forms::Label^ Title;

				System::Windows::Forms::Button^ input1;

				System::Windows::Forms::CheckBox^ input2;

				System::Windows::Forms::ComboBox^ input3;

				System::Windows::Forms::ComboBox^ input4;

				System::Windows::Forms::ComboBox^ input5;

				System::Windows::Forms::TextBox^ input6;

				System::Windows::Forms::TableLayoutPanel^  table;

				PROFILE_END();

 

				

				PROFILE_BEGIN(second);

				ColumnTitles->AddRange( myArr );

				table = gcnew System::Windows::Forms::TableLayoutPanel();

				table->Location = System::Drawing::Point(TableX, TableY);

				table->ColumnCount = NumCols;

				table->RowCount = NumRows;

				table->AutoScroll = true;

				PROFILE_END();

 

 

 

				this->SuspendLayout();

				PROFILE_BEGIN(third);

 

				// Create column titles and format widths of table columns

				for ( i=0; i<NumCols; i++  )

				{

PROFILE_BEGIN(third_a);

					Title = gcnew System::Windows::Forms::Label();

					Title->Text = ColumnTitles[i];

					Title->AutoSize = true;

					if ( i == 0 )

					{

						Title->Location = System::Drawing::Point(TitleX+10, TitleY);

						Spacing = ColWidth[i];

					}

					else

					{

						Title->Location = System::Drawing::Point(TitleX + Spacing, TitleY);

						Spacing += ColWidth[i];

					}

					PROFILE_END();

					PROFILE_BEGIN(third_b);

					table->ColumnStyles->Add(gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, (float) ColWidth[i]));

					this->tabPage1->Controls->Add(Title);

					PROFILE_END();

				}

				PROFILE_END();

				table->Size = System::Drawing::Size(Spacing + 50, TableHeight);
 

				PROFILE_BEGIN(third_c); 

				for ( i=0; i<NumRows; i++  )

				{

					PROFILE_BEGIN(third_d);

					table->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Absolute, (float) RowHeight)));

 

					

					input1 = gcnew System::Windows::Forms::Button();

					if ( i < 9 )

					{

						input1->Text = "inupt_0" + (i+1).ToString();

					}

					else if ( i < 32 )

					{

						input1->Text = "inupt_" + (i+1).ToString();

					}

					else if ( i < 41 )

					{

						input1->Text = "inupt1_0" + (i-31).ToString();

					}

					else

					{

						input1->Text = "inupt1_" + (i-31).ToString();

					}

					input1->AutoSize = true;

					input1->FlatAppearance->BorderSize = 0;

					input1->FlatStyle = System::Windows::Forms::FlatStyle::Flat;

					input1->TextAlign = System::Drawing::ContentAlignment::TopLeft;

					

					table->Controls->Add(input1, 0, i);

					PROFILE_END();

 

					PROFILE_BEGIN(third_e);

					input2 = gcnew System::Windows::Forms::CheckBox();

					input2->Checked = false;

					table->Controls->Add(input2, 1, i);

					PROFILE_END();

 

					PROFILE_BEGIN(third_f);

					input3 = gcnew System::Windows::Forms::ComboBox();

					input3->DropDownStyle = ComboBoxStyle::DropDownList;

					input3->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					input3->Items->Add("a");

					input3->Items->Add("b");

					input3->Items->Add("c");

					input3->Items->Add("d");

					input3->Items->Add("e");

					input3->Items->Add("f");

					input3->Items->Add("g");

					input3->Items->Add("h");

					input3->Items->Add("i");

					table->Controls->Add(input3, 2, i);

					PROFILE_END();
 

					PROFILE_BEGIN(third_g); 

					input4 = gcnew System::Windows::Forms::ComboBox();

					input4->DropDownStyle = ComboBoxStyle::DropDownList;

					input4->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					input4->Items->AddRange( this->DefaultLayouts );

					table->Controls->Add(input4, 3, i);

					PROFILE_END();
 

					PROFILE_BEGIN(third_h); 

					input5 = gcnew System::Windows::Forms::ComboBox();

					input5->DropDownStyle = ComboBoxStyle::DropDownList;

					input5->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

					input5->Items->Add("1");

					input5->Items->Add("2");

					table->Controls->Add(input5, 4, i);

 

					input6 = gcnew System::Windows::Forms::TextBox();

					input6->Text = "";

					table->Controls->Add(input6, 5, i);

					PROFILE_END();

				}

				PROFILE_END();

 

				PROFILE_BEGIN(fourth);

				this->tabPage1->Controls->Add(table);

				Table1Index = this->tabPage1->Controls->Count-1;

				this->ResumeLayout(false);

				PROFILE_END();

Open in new window

0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
Moderator: we are working on this thread. I am requesting not to close it. Thanks
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
I may be wrong in my hypothesis that gcnew were causing the most delay. what i did this time is wrapping ONLY the gcnew statement with the profiler call and wrapping the rest of the code seperately and this is what i noticed:
  third_d                                 1.0     43 us    0%     43 us    0%
  outofline                               1.0     10 us    0%     10 us    0%
  non_gc_d                                1.0    424 us    0%    424 us    0%

third_d is the gcnew statement, outofline is where text is getting assigned to the button that was created in third_d and non_gc_d is the statement that does not have gcnew statement that is adding control Controls->Add...
As it appears, the last one is taking the most time and not the gcnew..
                                for ( i=0; i<NumRows; i++  )

				{
 

	                                PROFILE_BEGIN(third_d);

					table->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Absolute, (float) RowHeight)));

 					PROFILE_END();

					PROFILE_BEGIN(outofline);

					input1 = gcnew System::Windows::Forms::Button();

					PROFILE_END();

					if ( i < 9 )

					{

						input1->Text = "inupt_0" + (i+1).ToString();

					}

					else if ( i < 32 )

					{

						input1->Text = "inupt_" + (i+1).ToString();

					}

					else if ( i < 41 )

					{

						input1->Text = "inupt1_0" + (i-31).ToString();

					}

					else

					{

						input1->Text = "inupt1_" + (i-31).ToString();

					}

					input1->AutoSize = true;

					input1->FlatAppearance->BorderSize = 0;

					input1->FlatStyle = System::Windows::Forms::FlatStyle::Flat;

					input1->TextAlign = System::Drawing::ContentAlignment::TopLeft;

					PROFILE_BEGIN(non_gc_d);

					table->Controls->Add(input1, 0, i);

					PROFILE_END();

                                   }

Open in new window

0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
Keep in mind that 1 us is only one millionth of a second.

third_h is taking one second, let's find out which calls inside this block take the most time, by replacing the third_h block by this one:


PROFILE_BEGIN(third_h);
 

PROFILE_BEGIN(third_h1);

input5 = gcnew System::Windows::Forms::ComboBox();

input5->DropDownStyle = ComboBoxStyle::DropDownList;

input5->Anchor = System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right | System::Windows::Forms::AnchorStyles::Top;

PROFILE_END();
 

PROFILE_BEGIN(third_h2);

input5->Items->Add("1");

input5->Items->Add("2");

PROFILE_END();
 

PROFILE_BEGIN(third_h3);

table->Controls->Add(input5, 4, i);

PROFILE_END();
 

PROFILE_BEGIN(third_h4);

input6 = gcnew System::Windows::Forms::TextBox();

input6->Text = "";

PROFILE_END();
 

PROFILE_BEGIN(third_h5);

table->Controls->Add(input6, 5, i);

PROFILE_END();
 

PROFILE_END();

Open in new window

0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
I had to take out some of the previous profiler calls because the compiler was complaining that there are too many constructor and destructor calls in the function. The new output is:

      third_h                                47.0    981 us    0%    979 ms    6%
      third_h1                             47.0      3 ms    0%      3 ms    0%
      third_h2                             47.0    303 us    0%    303 us    0%
      third_h3                             47.0    486 ms    3%    486 ms    3%
      third_h4                             47.0      2 ms    0%      2 ms    0%
      third_h5                             47.0    487 ms    3%    487 ms    3%

If you are interested in the total time also, its:

call tree                                  hits       self time      total time
<root>                                      1.0     17 s   106%     33 s   206%
  GUI_IP::Form1::Form1_Load                 1.0     14 s    84%     16 s   100%
     first                                   1.0    445 us    0%    445 us    0%
    second                                  1.0     49 us    0%     49 us    0%
    third_d                                47.0    155 ms    1%    155 ms    1%
    outofline                              47.0    506 us    0%    506 us    0%
    non_gc_d                               47.0    475 ms    3%    475 ms    3%
    third_e                                47.0    579 us    0%    579 us    0%
    non_gc_e                               47.0    477 ms    3%    477 ms    3%
    third_f                                47.0      3 ms    0%      3 ms    0%
    non_gc_f                               47.0    526 ms    3%    526 ms    3%
    third_h                                47.0    981 us    0%    979 ms    6%
      third_h1                             47.0      3 ms    0%      3 ms    0%
      third_h2                             47.0    303 us    0%    303 us    0%
      third_h3                             47.0    486 ms    3%    486 ms    3%
      third_h4                             47.0      2 ms    0%      2 ms    0%
      third_h5                             47.0    487 ms    3%    487 ms    3%
0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
It seems table->Controls->Add is the culprit. We can do a final analysis on how much time is spent in this function for all the tabs, using a small wrapper function around table->Controls->Add, as indicated below  (sorry, I have not .NET experience yet, this is pseudo code!).

Then, replace all direct calls to table->Controls->Add (in all the tabs) with calls to the wrapper function.
For example,

table->Controls->Add(input6, 5, i);

would be replaced with

AddControlToTable(input6, table, 5, i);

If this confirms that table->Controls->Add is taking all the time, then we need to find a way to speed it up, but let's first get the final confirmation.


// may not compile, but the idea of the wrapper should be clear...

void AddControlToTable(System::Windows::Forms::Control* control, System::Windows::Forms::TableLayoutPanel* table, int column, int row)

{

    PROFILE_FUNC(); // times how much time is taken by table->Controls->Add

    table->Controls->Add(control, column, row);

}

Open in new window

0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
that does seem to be the case:

      third_h                                47.0      1 ms    0%    971 ms    6%
      third_h1                             47.0      3 ms    0%      3 ms    0%
      third_h2                             47.0    297 us    0%    297 us    0%
      GUI_IP::Form1::AddControlToTable     94.0    966 ms    6%    966 ms    6%
      third_h4                             47.0      1 ms    0%      1 ms    0%

0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
What I meant was to replace table->Controls->Add with AddControlToTable everywhere (in all the code for all the tabs).
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
so it does seem like the Controls->Add is the culprit. Its taking 17 out of 19 secs the app takes to come up.

flat profile                               hits       self time      total time
<root>                                      1.0     19 s    98%     38 s   198%
GUI_IP::Form1::Form1_Load                   1.0      2 s    11%     19 s   100%
first                                       1.0    422 us    0%    422 us    0%
second                                      1.0     60 us    0%     60 us    0%
third_d                                    47.0    188 ms    1%    188 ms    1%
outofline                                  47.0    522 us    0%    522 us    0%
non_gc_d                                   47.0    771 us    0%    591 ms    3%
GUI_IP::Form1::AddControlToTable         1599.0     17 s    88%     17 s    88%
third_e                                    47.0    622 us    0%    622 us    0%
non_gc_e                                   47.0    320 us    0%    564 ms    3%
third_f                                    47.0      3 ms    0%      3 ms    0%
non_gc_f                                   47.0    769 us    0%    525 ms    3%
third_h                                    47.0      1 ms    0%      1 s     6%
third_h1                                   47.0      3 ms    0%      3 ms    0%
third_h2                                   47.0    246 us    0%    246 us    0%
third_h4                                   47.0      2 ms    0%      2 ms    0%

call tree                                  hits       self time      total time
<root>                                      1.0     19 s    98%     38 s   198%
  GUI_IP::Form1::Form1_Load                 1.0      2 s    11%     19 s   100%
    first                                   1.0    422 us    0%    422 us    0%
    second                                  1.0     60 us    0%     60 us    0%
    third_d                                47.0    188 ms    1%    188 ms    1%
    outofline                              47.0    522 us    0%    522 us    0%
    non_gc_d                               47.0    771 us    0%    591 ms    3%
      GUI_IP::Form1::AddControlToTable     47.0    590 ms    3%    590 ms    3%
    third_e                                47.0    622 us    0%    622 us    0%
    non_gc_e                               47.0    320 us    0%    564 ms    3%
      GUI_IP::Form1::AddControlToTable     47.0    564 ms    3%    564 ms    3%
    third_f                                47.0      3 ms    0%      3 ms    0%
    non_gc_f                               47.0    769 us    0%    525 ms    3%
      GUI_IP::Form1::AddControlToTable     47.0    524 ms    3%    524 ms    3%
    GUI_IP::Form1::AddControlToTable     1364.0     14 s    74%     14 s    74%
    third_h                                47.0      1 ms    0%      1 s     6%
      third_h1                             47.0      3 ms    0%      3 ms    0%
      third_h2                             47.0    246 us    0%    246 us    0%
      GUI_IP::Form1::AddControlToTable     94.0      1 s     6%      1 s     6%
      third_h4                             47.0      2 ms    0%      2 ms    0%
0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
According to this link

http://www.pcreview.co.uk/forums/thread-2667009.php

a way to speed up the dynamic adding of controls is to fill the containers bottom up instead of top-down.
So instead of adding a tab to the form, and then adding controls to the tab, you should first add the controls to the tab, and then add the tab to the form.

Also, according to the same link, it helps to not resize the form after you have added all the controls (because this triggers a repaint). Instead, you should set the desired size of the form before adding the tabs to the form.

The key part of the above link are these lines:

view.PerformLayout(); <--- (1)
splitContainer.Panel2.Controls.Add(view);
splitContainer.Panel2.ResumeLayout(false); <--- (2)

(1) = perform layout on the control before it's added to parent
(2) = after added to parent, do not do any layout processing and the
redundant re-paints dont get invoked (hopefully).

I cannot check these hints on my computer (I'm on linux), but it seems worth it to try this out (although in fact I would assume the SuspendLayout would already take care of all this...)

I would first try the first hint, and see if it improves things, before trying the second hint.
0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
from what i saw, there wasn't much change with either of these approaches, unless i am implementing them wrong. So AddControlsToLayout is the function i am calling for each table->Controls->Add(control, column, row). I changed that function to:
control->PerformLayout();
table->Controls->Add(control,column,row);
and the time for this function is still the same as before. As you had suggested, i tried to just do a perform layout first and then do add control before setting the resume layout to false, but that had no difference.
0
 
LVL 1

Accepted Solution

by:
maartennieber earned 500 total points
Comment Utility
I think the idea of the link (http://www.pcreview.co.uk/forums/thread-2667009.php) is to call view.PerformLayout() once before all the 1600 calls to Controls.Add.
Therefore, you should move view.PerformLayout() out of the AddControlsToLayout function.

Frankly, I have little confidence that this approach will help (as I indicated before), but I see nothing better. Maybe you need to ask someone else to help you to optimize the Controls.Add, on EE or on a .NET specific forum (I am not an expert on .NET).


0
 
LVL 1

Author Comment

by:funcoding
Comment Utility
Thanks maartennieber. I'll have to repost this with focus on optimizing the controls. I appreciate all the help in narrowing down the problem cause!
0
 
LVL 1

Expert Comment

by:maartennieber
Comment Utility
You're welcome! I hope you will find a definite solution.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

IP addresses can be stored in a database in any of several ways.  These ways may vary based on the volume of the data.  I was dealing with quite a large amount of data for user authentication purpose, and needed a way to minimize the storage.   …
Normally the drop down box control found in the .Net framework tools is able to select just one data and value at a time, which is displayed on the text area.   But what if you want to have multiple values to be selected in the drop down box? As …
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now