Avoiding runtime polymorphism performance issues

In the numerical code, running on thousands of processors for 10 s, I have a base class (Mesh) whose methods hit from 100 to 1000 milliseconds. There are currently two (Mesh_A, Mesh_B) derived classes, but this will eventually expand to three or four. Custom code cannot know until runtime whether its pointer to Mesh is actually Mesh_A or Mesh_B, but it never changes for the rest of the run.

Current implementation:

// Base class
class Mesh {
  ...
  virtual const Point& cell_centroid(int c) = 0;
}

// derived class A
class MeshA : public Mesh {
  ...
  Point& cell_centroid(int c) { return cell_centroids_[c]; }
}

// derived class B
class MeshB : public Mesh {
  ...
  Point& cell_centroid(int c) { return other_framework_->cell_centroid(c); }
}


// typical user class
class User {
  User(Mesh* mesh) : mesh_(mesh) {}

  void evalFunction() {
    for (int c=0; c!=mesh_->num_cells(); ++c) {
      double result = func(mesh_->cell_centroid(c));
      ...
    }
  }


  // Other methods which use mesh_->cell_centroid() very often, and in different ways.
}

MeshA , , . , (, - ?) ~ 15%, .

, , .

1: , . , " " , , . , Mesh, , cell_centroid() .

// Base class
class Mesh {
  ...
  virtual void evalFunction(double (*func)(Point&), std::vector<double>* result) = 0;
}

// derived class A
class MeshA : public Mesh {
  ...

  void evalFunction(double (*func)(Point&), std::vector<double>* result) {
    for (int c=0; c!=num_cells(); ++c) (*result)[c] = (*func)(cell_centroid(c));
  }

  Point& cell_centroid(int c) { return cell_centroids_[c]; }
}

// similar for B


// typical user class
class User {
  User(Mesh* mesh) : mesh_(mesh) {}

  void evalFunction() {
    m_->evalFunction();
  }
}

, Mesh - (, ), . , Mesh (15-20) 3 4 " ", Mesh . "", , Mesh , , .

2: Mesh_T. factory, User<MeshA> User<MeshB> . , , - , , .. .

3: , , Mesh MeshA MeshB, A B. , , Idea 1, User case/switch. , .

, !

+4
1

, mesh_ MeshA, MeshB, .

//

class User {
  User(Mesh* mesh) : mesh_(mesh) {}

  template<class dType>
  void evalFunction() {
    dType *myMesh = dynamic_cast<dType *>(mesh_);
    for (int c=0; c!=myMesh _->num_cells(); ++c) {
      double result = func(myMesh _->cell_centroid(c));
      ...
    }
  }
  void evalFunction() {
    if (dynamic_cast<MeshA *>(mesh_))
      evalFunction<MeshA>();
    if (dynamic_cast<MeshB *>(mesh_))
      evalFunction<MeshB>();
  }
}

evalFunction A B.

class User {
  User(Mesh* mesh) : mesh_(mesh) {}

  template<class dType>
  void evalFunction(dType *myMesh) {
    for (int c=0; c!=myMesh _->num_cells(); ++c) {
      double result = func(myMesh _->cell_centroid(c));
      ...
    }
  }
  void evalFunction() {
    MeshA *meshA = dynamic_cast<MeshA *>(mesh_);
    if (meshA)
      evalFunction<MeshA>(meshA);
    MeshB *meshB = dynamic_cast<MeshB *>(mesh_);
    if (meshB)
      evalFunction<MeshB>(meshB);
  }
}
+1

Source: https://habr.com/ru/post/1619080/


All Articles