Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Problems with performance

Reply
Thread Tools

Problems with performance

 
 
Tiib
Guest
Posts: n/a
 
      02-26-2013
On Tuesday, 26 February 2013 09:05:11 UTC+2, Seungbeom Kim wrote:
> On 2013-02-25 09:39, Tiib wrote:
> >
> > Change that leaves code same but makes it (hopefully) faster. Help the
> > compiler to optimize where it fails? For example you have such
> > code:
> > Now you replace it ... (assuming the arrays contain doubles) with that:
> > That maybe speeds it maybe not. Reading produced assembler or testing can
> > show.

>
> I'm just speculating, but reflecting that references just create aliases,
> I doubt that using references like this will affect the generated code
> in any significant way. (Creating a reference will not even trigger a
> prefetch, will it?) And if it actually does, the compiler must not have
> been doing a very good job even at merely grasping common subexpressions.


I asked for real code and what optimizations he has tried. He did ask as
return what I mean by optimizations. Above was example how optimizations
may look like.

> On the other hand, value copying instead of just aliasing (as for cay_j
> above) may have a better chance of improvement.


Real compilers manage to do that also pretty well.

 
Reply With Quote
 
 
 
 
Leandro
Guest
Posts: n/a
 
      02-26-2013
(E-Mail Removed):

"As others have mentioned, we're not seeing enough to really be able to
tell, but... "

OK, you're right. I tried to clean up the code of my class, removing all data members and leaving just the necessary to do the calculation. As a result, both versions run with the same speed (the difference were irrelevant).

"Certainly things like (un)fortuitous memory alignment in one case or
the other case can make a big difference. You may want to check how
that's different between the codes. You shouldn't really be seeing
that much of a performance hit just from being in the GUI application,
I assume the system is mostly not doing anything other than running
your thread and the GUI is mostly just sitting there, so there should
not be too much extra cache contention, although it's something to
consider."

I don't think the problem is with the GUI. I also tried to run the console version with a frame, but the difference holds. Another thing I can do is insert the "good" code at the GUI version and check the performance.

Considering the 30 days trial, I'll download Intel VTune and look for a tutorial. Tks.

----------------------------
Tiib:

"Change that leaves code same but makes it (hopefully) faster. Help the
compiler to optimize where it fails? For example you have such
code:..."

I've not tried this yet. First I'm trying to understand why the same code runs with completly different speed in the two versions. But you're right. In fact, someone said that TNT is not efficient, so I'll check other library(maybe Armadillo or Blitz++, don't know yet).

"t is not commercial but source can't be shown so free neither. What
remains ... ? Criminal or military goals? Those can pay even better
than commercial. Anyway we do not care about your whole code. Cut out
the part that you want to optimize in a way that we can compile it and
run. "

This is an academic project, but there are other people that owns the project. I cut out the part I want to optimize, but then the both versions runs with the same speed. I'll try other things and, if it doesn't work, I'll cut out the part I want to optimize (leaving the most part unnecessary to a test).

----------------------------
Alain Ketterlin

"I had a quick look at this, and it doesn't seem very efficient.
Especially, allocating a 3D arrays of doubles (I guess) allocates a 2D
array of pointers (to rows of doubles), which itself causes the
allocation of a 1D array of pointer (to rows of pointers). "

Tks. You're right, I'll look for a better library.
 
Reply With Quote
 
 
 
 
Alain Ketterlin
Guest
Posts: n/a
 
      02-26-2013
Seungbeom Kim <(E-Mail Removed)> writes:

> On 2013-02-25 09:39, Öö Tiib wrote:

[...]
>> for(j = 1; j < Ny; j++)
>> {
>> for(k = 1; k < Nz; k++)
>> {
>> curl_h = cay[j]*(Hz[i][j][k] - Hz[i][j-1][k])
>> - caz[k]*(Hy[i][j][k] - Hy[i][j][k-1]);
>> // ...
>> // rest of the stuff
>> }
>> }
>>
>> Now you replace it ... (assuming the arrays contain doubles) with that:

[...]
>> for(j = 1; j < Ny; j++)
>> {
>> double cay_j = cay[j];
>> double (&Hz_i_j)[Nz] = Hz[i][j];
>> double (&Hz_i_j_1)[Nz] = Hz[i][j-1];
>> double (&Hy_i_j)[Nz] = Hy[i][j];
>>
>> for(k = 1; k < Nz; k++)
>> {
>> curl_h = cay_j*(Hz_i_j[k] - Hz_i_j_1[k])
>> - caz[k]*(Hy_i_j[k] - Hy_i_j[k-1]);
>> // ...
>> // rest of the stuff
>> }
>> }


> I'm just speculating, but reflecting that references just create aliases,
> I doubt that using references like this will affect the generated code
> in any significant way.


It will, and a lot. In the fragment above you have more array reference
that actual computations (like + - etc.). Consider a loop like:

for ( i=... )
for ( j=... )
... T.at(i,j) ...

(I use at(i,j) to abstract away the effective access). Now assume T is a
linearized array. This access is equivalent to:

T.data[i*N+j]

Calculating i*N on every iteration of the j loop costs something. What
Öô suggests is moving this computation out of the j loop.

Note that if the array is stored as a 1D array of pointers to 1D arrays
of doubles, the same argument applies. T[i][j] is:

*(*(T.rows+i)+j)

again, *(T.rows+i) could be hoisted out of the j loop (if that location
is not overwritten during the run of the loop -- unfortunately it is
difficult for a compiler to realize this, and that's where restrict is
useful).

There is a large amount of computation going on during array accesses,
and factoring as much as possible to put it out of the loop is one of
the major optimization opportunity.

(To the OP: the library you use just makes array accesses much more
costly than they should be, and probably prevents this kind of
optimization.)

> (Creating a reference will not even trigger a prefetch, will it?)


No.

> And if it actually does, the compiler must not have been doing a very
> good job even at merely grasping common subexpressions.


Common subexpressions are important, loop-invariant code motion is even
more, because it reduces the amount of code by a factor equal to the
number of iterations of the loop.

> On the other hand, value copying instead of just aliasing (as for cay_j
> above) may have a better chance of improvement.


This is actually no different from extracting a partial array access:
same idea, same potential gain.

-- Alain.
 
Reply With Quote
 
Leandro
Guest
Posts: n/a
 
      02-26-2013
OK, so I'm trying to improve the performance of the code. I would like to substitute TNT library for another, more efficient (as suggest by Alain Ketterlin). So I tried to use direct pointers to store the data. Unfortunately,the code with TNT runs ~3 times faster than using pointers. How could I change this code to get a better performance over TNT? I've followed the suggestions of Tiib and Alain Ketterlin (put some arrays in the outer loop) and the performance improved 10%~15%, but yet worse than using TNT (http://math.nist.gov/tnt/overview.html).

Code with 3 tests:

#include "tnt/tnt.h"
#include "TicTac.h"

using namespace std;
using namespace TNT;

inline double getCM(double* array, int m0, int m1, int i, int j, int k) {
return array[i + m0*j + m0*m1*k];
}
inline void setCM(double* array, int m0, int m1, int i, int j, int k, double value) {
array[i + m0*j + m0*m1*k] = value;
}
inline void addCM(double* array, int m0, int m1, int i, int j, int k, double value) {
array[i + m0*j + m0*m1*k] += value;
}
int main() {

int Npml = 10;
int NxTOTAL = 100;
int NyTOTAL = 150;
int NzTOTAL = 200;
int TMAX = 1000;
int jb = NyTOTAL - Npml - 1;
int jyh;
int i, j, k, t;
double curl_h;


/* TNT - TEST 1 */
// Array1D<double> gi3 = Array1D<double>(NxTOTAL, 1.0);
// Array1D<double> cax = Array1D<double>(NxTOTAL, 0.0);
// Array1D<double> cay = Array1D<double>(NyTOTAL, 0.0);
// Array1D<double> caz = Array1D<double>(NzTOTAL, 0.0);
//
// Array3D<double> Hx = Array3D<double>(NxTOTAL,NyTOTAL,NzTOTAL, 0.0);
// Array3D<double> Hy = Array3D<double>(NxTOTAL,NyTOTAL,NzTOTAL, 0.0);
// Array3D<double> Hz = Array3D<double>(NxTOTAL,NyTOTAL,NzTOTAL, 0.0);
//
// Array1D<double> gk2 = Array1D<double>(NzTOTAL, 1.0);
// Array1D<double> gk3 = Array1D<double>(NzTOTAL, 1.0);
//
// Array3D<double> idyh = Array3D<double>(NxTOTAL, Npml, NzTOTAL, 0.0);
//
// Array3D<double> Dy = Array3D<double>(NxTOTAL,NyTOTAL,NzTOTAL, 0.0);
//
// Array1D<double> gi2 = Array1D<double>(NxTOTAL, 1.0);
// Array1D<double> gj1 = Array1D<double>(NyTOTAL, 0.0);
//
// TicTac tt;
// tt.Tic("TNT: ");
// for (t = 0; t < TMAX; t++) {
// for(i = 1; i < NxTOTAL; i++) {
// for(j = jb+1; j < NyTOTAL; j++) {
// jyh = j - jb - 1;
// for(k = 1; k < NzTOTAL; k++)
// {
// curl_h = caz[k]*(Hx[i][j][k] - Hx[i][j][k-1]) -
// cax[i]*(Hz[i][j][k] - Hz[i-1][j][k]);
// idyh[i][jyh][k] = idyh[i][jyh][k] + curl_h;
// Dy[i][j][k] = gi3[i]*gk3[k]*Dy[i][j][k] +
// gi2[i]*gk2[k]*(curl_h + gj1[j]*idyh[i][jyh][k]);
// }
// }
// }
// }
// tt.Tac();



/* C-ARRAY - TEST 2 */
// double* gi3 = new double[NxTOTAL];
// double* cax = new double[NxTOTAL];
// double* cay = new double[NyTOTAL];
// double* caz = new double[NzTOTAL];
//
// double* Hx = new double[NxTOTAL*NyTOTAL*NzTOTAL];
// double* Hy = new double[NxTOTAL*NyTOTAL*NzTOTAL];
// double* Hz = new double[NxTOTAL*NyTOTAL*NzTOTAL];
//
// double* gk2 = new double[NxTOTAL];
// double* gk3 = new double[NxTOTAL];
//
// double* idyh = new double[NxTOTAL*NyTOTAL*NzTOTAL];
// double* Dy = new double[NxTOTAL*NyTOTAL*NzTOTAL];
//
// double* gi2 = new double[NxTOTAL];
// double* gj1 = new double[NxTOTAL];
//
// TicTac tt;
// tt.Tic("Array");
// for (t = 0; t < TMAX; t++) {
// for(i = 1; i < NxTOTAL; i++) {
// for(j = jb+1; j < NyTOTAL; j++) {
// jyh = j - jb - 1;
// for(k = 1; k < NzTOTAL; k++)
// {
// curl_h = caz[k]*(getCM(Hx, NxTOTAL, NyTOTAL, i, j, k) - getCM(Hx, NxTOTAL, NyTOTAL, i, j, k-1)) -
// cax[i]*(getCM(Hz, NxTOTAL, NyTOTAL, i, j, k) - getCM(Hz, NxTOTAL,NyTOTAL, i-1, j, k));
//
// addCM(idyh, NxTOTAL, NyTOTAL, i, jyh, k, curl_h);
//
// double value = gi3[i]*gk3[k]*getCM(Dy, NxTOTAL, NyTOTAL, i, j, k) +
// gi2[i]*gk2[k]*(curl_h + gj1[j]*getCM(idyh, NxTOTAL, NyTOTAL, i, jyh, k));
// setCM(Dy, NxTOTAL, NyTOTAL, i, j, k, value);
//
// }
// }
// }
// }
// tt.Tac();
//
// delete[] gi3;
// delete[] cax;
// delete[] cay;
// delete[] caz;
//
// delete[] Hx;
// delete[] Hy;
// delete[] Hz;
//
// delete[] gk2;
// delete[] gk3;
//
// delete[] idyh;
// delete[] Dy;
//
// delete[] gi2;
// delete[] gj1;




/* C-ARRAY (IMPROVED) - TEST 3*/
double* gi3 = new double[NxTOTAL];
double* cax = new double[NxTOTAL];
double* cay = new double[NyTOTAL];
double* caz = new double[NzTOTAL];

double* Hx = new double[NxTOTAL*NyTOTAL*NzTOTAL];
double* Hy = new double[NxTOTAL*NyTOTAL*NzTOTAL];
double* Hz = new double[NxTOTAL*NyTOTAL*NzTOTAL];

double* gk2 = new double[NxTOTAL];
double* gk3 = new double[NxTOTAL];

double* idyh = new double[NxTOTAL*NyTOTAL*NzTOTAL];
double* Dy = new double[NxTOTAL*NyTOTAL*NzTOTAL];

double* gi2 = new double[NxTOTAL];
double* gj1 = new double[NxTOTAL];

TicTac tt;
tt.Tic("Array (improved): ");
for (t = 0; t < TMAX; t++) {
for(i = 1; i < NxTOTAL; i++) {
for(j = jb+1; j < NyTOTAL; j++) {
double* Dy_ij = Dy + (i + j*NxTOTAL);
double* Hx_ij = Hx + (i + j*NxTOTAL);
double* Hz_ij = Hz + (i + j*NxTOTAL);
double* Hz_i1_j = Hz + (i - 1 + j*NxTOTAL);

double jyh = j - jb - 1;
for(k = 1; k < NzTOTAL; k++)
{
double curl_h = caz[k]*(Hx_ij[NxTOTAL*NyTOTAL*k] - Hx_ij[NxTOTAL*NyTOTAL*k-1]) -
cax[i]*(Hz_ij[NxTOTAL*NyTOTAL*k] - Hz_i1_j[NxTOTAL*NyTOTAL*k]);

addCM(idyh, NxTOTAL, NyTOTAL, i, jyh, k, curl_h);

double value = gi3[i]*gk3[k]*Dy_ij[NxTOTAL*NyTOTAL*k] +
gi2[i]*gk2[k]*(curl_h + gj1[j]*getCM(idyh, NxTOTAL, NyTOTAL, i, jyh, k));
Dy_ij[NxTOTAL*NyTOTAL*k] = value;
}
}
}
}
tt.Tac();

delete[] gi3;
delete[] cax;
delete[] cay;
delete[] caz;

delete[] Hx;
delete[] Hy;
delete[] Hz;

delete[] gk2;
delete[] gk3;

delete[] idyh;
delete[] Dy;

delete[] gi2;
delete[] gj1;
}
----------------
TicTac just measures time and print:

class TicTac {
private:
string message;
double tstart;
double tend;
public:
TicTac();
~TicTac();
void Tic(string msg);
void Tac();
};

void TicTac::Tic(string msg) {
message = msg;
tstart = (double)clock()/CLOCKS_PER_SEC;
}

void TicTac::Tac() {
tend = (double)clock()/CLOCKS_PER_SEC;
cout << message << ". TIME: " << (tend-tstart) << "s" << endl;
}


Tks
 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      02-26-2013
On 2/26/2013 11:04 AM, Leandro wrote:
> OK, so I'm trying to improve the performance of the code. I would
> like to substitute TNT library for another, more efficient (as
> suggest by Alain Ketterlin). So I tried to use direct pointers to
> store the data. Unfortunately, the code with TNT runs ~3 times faster
> than using pointers. How could I change this code to get a better
> performance over TNT? I've followed the suggestions of Tiib and
> Alain Ketterlin (put some arrays in the outer loop) and the
> performance improved 10%~15%, but yet worse than using TNT
> (http://math.nist.gov/tnt/overview.html).


Give it another thought. Take a look at the following.

double a[N*M] = {};
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
do_something( a[i*M + j] ); // pay attention here
}
}

And compare it to

double a[N*M] = {};
for (int i = 0; i < N; i++)
{
double* pai = a + i*M;
for (int j = 0; j < M; j++)
{
do_something( pai[j] ); // pay attention here too
}
}

What do you see different here?

I do not want to get your hopes too much up, so to speak, but IME tricks
like that *have shown* improvement (although not three-fold) over the
use of full indexing arithmetic in the innermost loop.

> [..]


V
--
I do not respond to top-posted replies, please don't ask
 
Reply With Quote
 
Tiib
Guest
Posts: n/a
 
      02-26-2013
On Tuesday, 26 February 2013 18:04:08 UTC+2, Leandro wrote:
> OK, so I'm trying to improve the performance of the code.
> I would like to substitute TNT library for another, more efficient
> (as suggest by Alain Ketterlin). So I tried to use direct pointers
> to store the data. Unfortunately, the code with TNT runs ~3 times
> faster than using pointers. How could I change this code to get a
> better performance over TNT? I've followed the suggestions of Tiib
> and Alain Ketterlin (put some arrays in the outer loop) and the
> performance improved 10%~15%, but yet worse than using TNT
> (http://math.nist.gov/tnt/overview.html).


You want to beat someone then you need to master the whole thing,
that is impossible to achieve by just single thread in clc++. For
example how to replace multiplication with addition:

for ( t = 0; t < TMAX; t++ ) {
for ( i = 1; i < NxTOTAL; i++ ) {
// multiply once
double* Dy_ij = Dy + (i + jb*NxTOTAL);
double* Hx_ij = Hx + (i + jb*NxTOTAL);
double* Hz_ij = Hz + (i + jb*NxTOTAL);
double* Hz_i1_j = Hz + (i - 1 + jb*NxTOTAL);
for ( j = jb+1; j < NyTOTAL; j++ ) {
// just add rest of the time
Dy_ij += NxTOTAL;
Hx_ij += NxTOTAL;
Hz_ij += NxTOTAL;
Hz_i1_j += NxTOTAL;

In general ... profile -> read books & optimize -> profile in cycle until
you can not make it any better.
 
Reply With Quote
 
Alain Ketterlin
Guest
Posts: n/a
 
      02-27-2013
Leandro <(E-Mail Removed)> writes:

> inline double getCM(double* array, int m0, int m1, int i, int j, int k) {
> return array[i + m0*j + m0*m1*k];
> }


Leandro, this is "wrong". C/C++ stores arrays in row major mode, so if
the array is of size N*M*P, element [i][j][k] is at i*M*P + j*P + k (the
problem is the same inside the loop).

Having it the wrong way completely kills spatial locality, it is
therefore not surprising you get worse results, even though your numbers
are probably right.

Also, in a first experiment, leave it the compiler to move code out of
the loops (compile with -O1 at least, gcc should be able to cope).

-- Alain.
 
Reply With Quote
 
Seungbeom Kim
Guest
Posts: n/a
 
      04-08-2013
On 2013-02-26 04:00, Alain Ketterlin wrote:
> Consider a loop like:
>
> for ( i=... )
> for ( j=... )
> ... T.at(i,j) ...
>
> (I use at(i,j) to abstract away the effective access). Now assume T is a
> linearized array. This access is equivalent to:
>
> T.data[i*N+j]
>
> Calculating i*N on every iteration of the j loop costs something. What
> Öô suggests is moving this computation out of the j loop.


I have experimented with a simple program that calculates element-wise
multiplication of two matrices.

// Version A:
for (size_t i = 0; i < M; ++i) {
for (size_t j = 0; j < N; ++j) {
C[N * i + j] = A[N * i + j] * B[N * i + j];
}
}

// Version B:
for (size_t i = 0; i < M; ++i) {
const T* A_i = &A[N * i];
const T* B_i = &B[N * i];
T* C_i = &C[N * i];
for (size_t j = 0; j < N; ++j) {
C_i[j] = A_i[j] * B_i[j];
}
}

(T=double, M=N=256, repeating for 10000 times)

95% confidence intervals of the running time based on 100 trials are:

A B
g++ -O2: 1.594±0.005 1.592±0.005
g++ -O3: 1.648±0.005 1.607±0.005
(using g++ 4.6.3 on x86_64 Linux)

Under g++ -O2, the difference between the two versions are negligible.
However, g++ -O3 makes both worse, and makes Version A much worse.

Anyway, this shows that compilers may not always be as smart as I wish
them to be.

--
Seungbeom Kim
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      04-09-2013
On Tuesday, 26 February 2013 12:00:40 UTC, Alain Ketterlin wrote:
> Seungbeom Kim <(E-Mail Removed)> writes:


> > On 2013-02-25 09:39, Tiib wrote:

> [...]
> >> for(j = 1; j < Ny; j++)
> >> {
> >> for(k = 1; k < Nz; k++)
> >> {
> >> curl_h = cay[j]*(Hz[i][j][k] - Hz[i][j-1][k])
> >> - caz[k]*(Hy[i][j][k] - Hy[i][j][k-1]);
> >> // ...
> >> // rest of the stuff
> >> }
> >> }


> >> Now you replace it ... (assuming the arrays contain doubles) with that:

> [...]
> >> for(j = 1; j < Ny; j++)
> >> {
> >> double cay_j = cay[j];
> >> double (&Hz_i_j)[Nz] = Hz[i][j];
> >> double (&Hz_i_j_1)[Nz] = Hz[i][j-1];
> >> double (&Hy_i_j)[Nz] = Hy[i][j];


> >> for(k = 1; k < Nz; k++)
> >> {
> >> curl_h = cay_j*(Hz_i_j[k] - Hz_i_j_1[k])
> >> - caz[k]*(Hy_i_j[k] - Hy_i_j[k-1]);
> >> // ...
> >> // rest of the stuff
> >> }
> >> }


> > I'm just speculating, but reflecting that references just
> > create aliases, I doubt that using references like this will
> > affect the generated code in any significant way.


> It will, and a lot.


If it does, then there's something seriously wrong with the
quality of the compiler. Hoisting loop invariants was
a standard optmization technique twenty or thirty years ago.

> In the fragment above you have more array reference
> that actual computations (like + - etc.). Consider a loop like:


> for ( i=... )
> for ( j=... )
> ... T.at(i,j) ...


> (I use at(i,j) to abstract away the effective access). Now assume T is a
> linearized array. This access is equivalent to:


> T.data[i*N+j]


> Calculating i*N on every iteration of the j loop costs
> something. What suggests is moving this computation out of
> the j loop.


Except that pretty much every compiler in the world will do this
for you. And typically, when the compiler does it, it can do it
better than if you try to do it by hand, since it knows the
finality of the references and pointers it creates.

> Note that if the array is stored as a 1D array of pointers to 1D arrays
> of doubles, the same argument applies. T[i][j] is:


> *(*(T.rows+i)+j)


> again, *(T.rows+i) could be hoisted out of the j loop (if that location
> is not overwritten during the run of the loop -- unfortunately it is
> difficult for a compiler to realize this, and that's where restrict is
> useful).


> There is a large amount of computation going on during array accesses,
> and factoring as much as possible to put it out of the loop is one of
> the major optimization opportunity.


> (To the OP: the library you use just makes array accesses much more
> costly than they should be, and probably prevents this kind of
> optimization.)


> > (Creating a reference will not even trigger a prefetch, will it?)


> No.


> > And if it actually does, the compiler must not have been doing a very
> > good job even at merely grasping common subexpressions.


> Common subexpressions are important, loop-invariant code motion is even
> more, because it reduces the amount of code by a factor equal to the
> number of iterations of the loop.


> > On the other hand, value copying instead of just aliasing (as for cay_j
> > above) may have a better chance of improvement.


> This is actually no different from extracting a partial array access:
> same idea, same potential gain.


Extracting the value has an important benefit; when the compiler
must access the values, it has to take into account possible
aliasing. Thus, in `idx[i][j][k] = ...` and `D[i][j][k] = ...`,
the compiler will probably have to assume that anything
expression that references into any of the other arrays might
have different results.

This depends on the definitions of the other arrays. If e.g.
`Hz` and `idx` are both C style arrays&mdash;_not_ pointers
which point to the first element, but the actual data
definitions&mdash;then the compiler can know that they don't
alias one another. Otherwise, it has to assume the worst, and
reread the elements each time through the loop. Manually
hoisting the reads of `gj3[j]` etc. out of the inner most loop
might make a significant difference, because the compiler
probably cannot do this (since if all it has are pointers, it
has to assume that one of the other assignments in the innermost
loop might modify this value). Depending on the dimensions, it
might actually be worth copying `Hz[i][j]` et al. into one
dimensional local arrays (which the compiler can see arn't being
modified).

Even better, of course, would be if the compiler has extensions
which allow you to tell it that there isn't any aliasing. C++11
didn't adopt C's `restrict` keyword, but this is one place where
it could help enormously (and some C++ compilers might support
it as an extension).

--
James
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Performance Tutorials Services - Boosting Performance by DisablingUnnecessary Services on Windows XP Home Edition Software Engineer Javascript 0 06-10-2011 02:18 AM
Throughput of your Gigabit switch? (performance problems with 3508G-XL) Thomas Arens Cisco 18 10-06-2004 06:23 PM
Async performance problems. Erik Tamminga Cisco 9 04-19-2004 11:15 PM
catalyst 2948G throughput performance problems ? Martin Bilgrav Cisco 1 12-30-2003 01:51 AM
Web Form Performance Versus Single File Performance jm ASP .Net 1 12-12-2003 11:14 PM



Advertisments