Inlining + Reorganization + Roofline
This commit is contained in:
committed by
Linus Baumberger
parent
43f11a661b
commit
b86c856e08
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#include "vector2d.hpp"
|
||||
|
||||
struct Obstacle {
|
||||
Vector2d start; // First endpoint of the obstacle segment.
|
||||
Vector2d end; // Second endpoint of the obstacle segment.
|
||||
Vector2d obstacle_v; // Direction vector of the segment: end - start.
|
||||
double length_sq_inv; // Inverse squared length of the segment, used for projection.
|
||||
|
||||
// Default constructor: creates a degenerate obstacle at the origin.
|
||||
// This is mainly used for array allocation before assigning real obstacles.
|
||||
Obstacle() : start(0, 0), end(0, 0), obstacle_v(0, 0), length_sq_inv(0.0) {}
|
||||
|
||||
// Constructs an obstacle as a finite line segment from s to e.
|
||||
//
|
||||
// The segment direction and inverse squared length are precomputed and cached because
|
||||
// they are reused when projecting pedestrian positions onto the obstacle.
|
||||
//
|
||||
// @param s The first endpoint of the obstacle segment.
|
||||
// @param e The second endpoint of the obstacle segment.
|
||||
//
|
||||
Obstacle(Vector2d s, Vector2d e) : start(s), end(e) {
|
||||
obstacle_v = end - start;
|
||||
double length_sq = obstacle_v.dot(obstacle_v);
|
||||
length_sq_inv = length_sq != 0.0 ? 1.0 / length_sq : 0.0;
|
||||
}
|
||||
|
||||
// Flop count: 5 ADDs, 5 MULTs
|
||||
//
|
||||
// Finds the point on this finite obstacle segment that is closest to p.
|
||||
//
|
||||
// The method projects the vector (p - start) onto the obstacle direction
|
||||
// vector, then clamps the projection factor to [0, 1] so that the returned
|
||||
// point lies on the finite segment.
|
||||
//
|
||||
// Note : If the obstacle is a single point, meaning start == end, length_sq_inv is zero
|
||||
// and the method returns start.
|
||||
//
|
||||
// @param p The point for which the closest obstacle point is computed.
|
||||
// @return The closest point on the obstacle segment to p.
|
||||
//
|
||||
Vector2d find_nearest_obstacle_point(const Vector2d &p) const {
|
||||
|
||||
// # 3 ADDs, 3 MULTs
|
||||
double projection = (p - start).dot(obstacle_v) * length_sq_inv;
|
||||
|
||||
if (projection < 0.0)
|
||||
projection = 0.0;
|
||||
else if (projection > 1.0)
|
||||
projection = 1.0;
|
||||
|
||||
// # 2 ADDs, 2 MULTs
|
||||
return start + obstacle_v * projection;
|
||||
}
|
||||
};
|
||||
|
||||
struct Board {
|
||||
double length; // Board length.
|
||||
double width; // Board width.
|
||||
Obstacle *obstacles; // Array of obstacles contained in the board.
|
||||
int n_obstacles; // Total number of obstacles
|
||||
|
||||
// Constructs a rectangular board of size length x width.
|
||||
//
|
||||
// The input array o contains n user-defined obstacles. The constructor copies
|
||||
// those obstacles and then appends the two horizontal borders of the board (bottom and top) as additional
|
||||
// obstacle segments:
|
||||
//
|
||||
// bottom: (0, 0) -> (length, 0)
|
||||
// top: (0, width) -> (length, width)
|
||||
//
|
||||
// Note: only the horizontal borders are modeled as obstacles. The vertical
|
||||
// borders are left open so pedestrians can enter and leave the walkway without
|
||||
// being affected by repulsive forces from those borders. This is consistent
|
||||
// with Fig. 2 in the paper, where the horizontal walkway boundaries are
|
||||
// emphasized but the vertical ends are not shown as walls.
|
||||
//
|
||||
// @param l The board length.
|
||||
// @param w The board width.
|
||||
// @param n The number of user-defined obstacles in o.
|
||||
// @param o Array of user-defined obstacles to copy into the board obstacles array.
|
||||
//
|
||||
Board(double l, double w, int n, Obstacle *o) : length(l), width(w), n_obstacles(n + 2) {
|
||||
obstacles = new Obstacle[n + 2];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
obstacles[i] = o[i];
|
||||
}
|
||||
|
||||
// Board borders: bottom, top.
|
||||
obstacles[n] = Obstacle(Vector2d(0, 0), Vector2d(l, 0));
|
||||
obstacles[n + 1] = Obstacle(Vector2d(0, w), Vector2d(l, w));
|
||||
}
|
||||
|
||||
// Releases the dynamically allocated obstacle array.
|
||||
~Board() { delete[] obstacles; }
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
|
||||
//
|
||||
// $\frac{1}{\tau_{\alpha}}$; $\tau_{\alpha} = 0.5s$
|
||||
//
|
||||
const double tau_alpha_inv = 2.0;
|
||||
|
||||
// $V^0_{\alpha \beta}$
|
||||
const double V0_AB = 2.1;
|
||||
|
||||
// $\sigma$
|
||||
const double SIGMA = 0.3;
|
||||
|
||||
//
|
||||
// $\frac{-1}{2\sigma}$
|
||||
//
|
||||
const double NEG_TWO_SIGMA_INV = -1.0 / (2 * SIGMA);
|
||||
|
||||
//
|
||||
// $\frac{-V^0_{\alpha\beta}}{2\sigma}$
|
||||
//
|
||||
const double NEG_V0_AB_div_TWO_SIGMA = V0_AB * NEG_TWO_SIGMA_INV;
|
||||
|
||||
// $U^0_{\alpha B}$
|
||||
const double U0_AB = 10.0;
|
||||
|
||||
// $R$
|
||||
const double R = 0.2;
|
||||
|
||||
//
|
||||
// $\frac{-1}{R}$
|
||||
//
|
||||
const double NEG_R_INV = -1.0 / R;
|
||||
|
||||
//
|
||||
// $\frac{-U^0_{\alpha B}}{R}$
|
||||
//
|
||||
const double NEG_U0_AB_div_R = -U0_AB / R;
|
||||
|
||||
// $-c$
|
||||
const double c_neg = -0.5;
|
||||
|
||||
// $\varphi$
|
||||
const double phi = 100.0 / 180.0 * M_PI;
|
||||
|
||||
// $cos(\varphi)$
|
||||
const double cos_phi = cos(phi);
|
||||
|
||||
//
|
||||
// $\frac{1}{cos(\varphi)}$
|
||||
//
|
||||
const double cos_phi_inv = 1 / cos(phi);
|
||||
|
||||
// $<v^0>$
|
||||
const double v0_mean = 1.34;
|
||||
|
||||
// $\sqrt{\theta}$
|
||||
const double v0_std_dev = 0.26;
|
||||
|
||||
// $\varDelta_{t}$
|
||||
const double delta_t = 2;
|
||||
|
||||
// $\varDelta_{t}^2$
|
||||
const double delta_t_sq = delta_t * delta_t;
|
||||
|
||||
// $dt$
|
||||
const double dt = 0.02;
|
||||
|
||||
// $-dt$
|
||||
const double dt_neg = -dt;
|
||||
|
||||
// $-c \cdot dt$
|
||||
const double c_neg_times_dt = c_neg * dt;
|
||||
|
||||
//
|
||||
// $\frac{1}{\tau_{\alpha}} \cdot dt$
|
||||
//
|
||||
const double dt_times_tau_alpha_inv = dt * tau_alpha_inv;
|
||||
|
||||
const double cost_add = 1;
|
||||
const double cost_mult = 1;
|
||||
const double cost_div = 1;
|
||||
|
||||
// https://acl.inf.ethz.ch/teaching/fastcode/knowledgebase/#:~:text=How%20do%20exp(x)%2C%20sin(x)%2C%20etc.%20count%20in%20the%20flopcount%20of%20an%20algorithm%3F
|
||||
const double cost_exp = 30;
|
||||
|
||||
// -O3 maps each sqrt() call to an instruction
|
||||
const double cost_sqrt = 1;
|
||||
|
||||
// Numerical tolerance used to avoid division by zero and unstable operations
|
||||
// when distances or norms are extremely small.
|
||||
const double EPS = 1e-9;
|
||||
|
||||
// Squared numerical tolerance
|
||||
const double EPS_SQ = EPS * EPS;
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
#include "board.hpp"
|
||||
#include "pedestrian.hpp"
|
||||
#include "vector2d.hpp"
|
||||
|
||||
// Note: force contributions are multiplied by dt inside each function because
|
||||
// this allows us to bake dt into precomputed constants and thus save two
|
||||
// multiplications in the main loop. Conceptually, each returned term is the
|
||||
// explicit-Euler approximation of the time integral of one force contribution
|
||||
// over a single simulation step.
|
||||
//
|
||||
// This is valid because integration is linear: the integral of a sum is the sum
|
||||
// of the integrals. Thus, summing F_i * dt for each contribution is equivalent
|
||||
// to computing dt * sum(F_i) after all force contributions have been accumulated.
|
||||
|
||||
// Computes the direction-dependent perception weight from Eq. (7) in the paper:
|
||||
//
|
||||
// $w(\vec{e}_{\alpha}, \vec{f}) = \begin{cases} 1.0, & \text{if } \vec{e}_{\alpha} \cdot \vec{f} \geq \|\vec{f}\| \cos(\varphi), \\ c, & \text{otherwise}. \end{cases}$
|
||||
//
|
||||
// where:
|
||||
// - $\vec{e}_{\alpha}$ is the desired direction of motion of the pedestrian,
|
||||
// - $\vec{f}$ is the force under consideration (e.g., the repulsive force from another pedestrian or an obstacle),
|
||||
// - $\varphi$ is half of the effective angle of sight,
|
||||
// - $c$ is the reduced weight factor for situations outside the field of view.
|
||||
//
|
||||
// The function returns:
|
||||
//
|
||||
// $w(\vec{e}_{\alpha}, \vec{f}).(-dt)$
|
||||
//
|
||||
// Note: the reason we multiply the perception weight by -dt is:
|
||||
// (1) the factor dt saves a multiplication by dt, in pedestrian_repulsion_dt and obstacle_repulsion_dt;
|
||||
// (2) the minus sign is applied because the repulsion routines (pedestrian_repulsion_dt and obstacle_repulsion_dt) compute and
|
||||
// pass the negated force direction to w(), matching the paper's w(e_alpha, -f) term. Returning -w() then converts that internally
|
||||
// negated force back to the correct signed result vector without needing to perform any vector negation, in order to meet the paper's formula.
|
||||
//
|
||||
// @param e : The desired direction of motion of the pedestrian.
|
||||
// @param f : The force under consideration (e.g., the repulsive force from another pedestrian or an obstacle).
|
||||
// @return The direction-dependent perception weight multiplied by -dt.
|
||||
//
|
||||
double w(Vector2d e, Vector2d f);
|
||||
|
||||
// Computes the acceleration term of the social force model
|
||||
// for pedestrian alpha (Eq. (2) in the paper):
|
||||
//
|
||||
// $\vec{F}^0_\alpha = \frac{1}{\tau_\alpha}(v^0_\alpha \vec{e}_\alpha - \vec{v}_\alpha)$
|
||||
//
|
||||
// where:
|
||||
// - $v^0_\alpha$ is the desired speed,
|
||||
// - $\vec{e}_\alpha$ is the desired direction,
|
||||
// - $\vec{v}_\alpha$ is the current velocity,
|
||||
// - $\tau_\alpha$ is the relaxation time.
|
||||
//
|
||||
// This function returns $\vec{F}^0_\alpha.dt$, i.e. the velocity increment caused by
|
||||
// the acceleration term during one simulation time step:
|
||||
//
|
||||
// $\vec{F}^0_\alpha.dt = \frac{dt}{\tau_\alpha}(v^0_\alpha \vec{e}_\alpha - \vec{v}_\alpha)$
|
||||
//
|
||||
// @param alpha : The pedestrian for which the acceleration contribution is computed.
|
||||
// @return The velocity increment caused by the acceleration term during one simulation time step.
|
||||
//
|
||||
Vector2d acceleration_term_dt(const Pedestrian &alpha);
|
||||
|
||||
// Computes the repulsive pedestrian-pedestrian effect
|
||||
// exerted by pedestrian beta on pedestrian alpha (Eq. (3) in the paper),
|
||||
// weighted by the direction-dependent perception factor from Eq. (7)-(8):
|
||||
//
|
||||
// $\vec{F}_{\alpha\beta}(\vec{e}_{\alpha}, \vec{r}_{\alpha \beta}) = w(\vec{e}_{\alpha}, -\vec{f}_{\alpha\beta}(\vec{r}_{\alpha \beta}))\vec{f}_{\alpha\beta}(\vec{r}_{\alpha \beta})$
|
||||
//
|
||||
// where:
|
||||
// - $\vec{r}_{\alpha \beta} = \vec{r}_\alpha - \vec{r}_\beta$ is the vector from beta's position to alpha's position,
|
||||
// - $\vec{e}_\alpha$ is the desired direction of pedestrian alpha,
|
||||
//
|
||||
// - $\vec{f}_{\alpha\beta}(\vec{r}_{\alpha \beta}) = -\nabla_{\vec{r}_{\alpha\beta}} V_{\alpha\beta}\left[b(\vec{r}_{\alpha\beta})\right]$ is the repulsive effect from beta on alpha (The expanded formula details are given in the code comments given inside the function's implementation in variants_baseline.cpp),
|
||||
//
|
||||
// - $w(\vec{e}_{\alpha}, -\vec{f}_{\alpha\beta}(\vec{r}_{\alpha \beta}))$ the direction-dependent perception weighting function, for which the formula is detailed in the w() function above.
|
||||
//
|
||||
// This function returns $\vec{F}_{\alpha\beta}(\vec{e}_{\alpha}, \vec{r}_{\alpha \beta}).dt$, i.e. the velocity increment caused by the repulsive pedestrian-pedestrian effect during one simulation time step:
|
||||
//
|
||||
// $\vec{F}_{\alpha\beta}(\vec{e}_{\alpha}, \vec{r}_{\alpha \beta}).dt = w(\vec{e}_{\alpha}, -\vec{f}_{\alpha\beta}(\vec{r}_{\alpha \beta}))\vec{f}_{\alpha\beta}(\vec{r}_{\alpha \beta}).dt$
|
||||
//
|
||||
// @param alpha : The pedestrian receiving the repulsive effect.
|
||||
// @param beta : The pedestrian producing the repulsive effect.
|
||||
// @return The velocity increment caused by the repulsive effect from pedestrian beta on alpha during one
|
||||
// simulation time step.
|
||||
//
|
||||
Vector2d pedestrian_repulsion_dt(const Pedestrian &alpha, const Pedestrian &beta);
|
||||
|
||||
// Computes the repulsive effect exerted by obstacle B
|
||||
// on pedestrian alpha (Eq. (5) in the paper), weighted by the direction-dependent perception factor from Eq. (7)-(8]:
|
||||
//
|
||||
// $\vec{F}_{\alpha B}(\vec{e}_{\alpha}, \vec{r}_{\alpha B}) = w(\vec{e}_{\alpha}, -\vec{F}_{\alpha B}(\vec{r}_{\alpha B}))\vec{F}_{\alpha B}(\vec{r}_{\alpha B})$
|
||||
//
|
||||
// where:
|
||||
// - $\vec{r}_{\alpha B} = \vec{r}_\alpha - \vec{r}^{\,\alpha}_B$ is the vector from the closest point on obstacle B (i.e., $\vec{r}^{\,\alpha}_B$) to pedestrian alpha's position,
|
||||
// - $\vec{e}_\alpha$ is the desired direction of pedestrian alpha,
|
||||
//
|
||||
// - $\vec{F}_{\alpha B}(\vec{r}_{\alpha B}) = -\nabla_{\vec{r}_{\alpha B}} U_{\alpha B}(||\vec{r}_{\alpha B}||)$ is the repulsive effect from obstacle B on alpha (The expanded formula details are given in the code comments given inside the function's implementation in variant_baseline.cpp),
|
||||
//
|
||||
// - $w(\vec{e}_{\alpha}, -\vec{F}_{\alpha B}(\vec{r}_{\alpha B}))$ the direction-dependent perception weighting function, for which the formula is detailed in the w() function above.
|
||||
//
|
||||
// This function returns $\vec{F}_{\alpha B}(\vec{e}_{\alpha}, \vec{r}_{\alpha B}).dt$, i.e. the velocity increment caused by the repulsive obstacle effect during one simulation time step:
|
||||
//
|
||||
// $\vec{F}_{\alpha B}(\vec{e}_{\alpha}, \vec{r}_{\alpha B}).dt = w(\vec{e}_{\alpha}, -\vec{F}_{\alpha B}(\vec{r}_{\alpha B}))\vec{F}_{\alpha B}(\vec{r}_{\alpha B}).dt$
|
||||
//
|
||||
// @param alpha : The pedestrian receiving the obstacle repulsive effect.
|
||||
// @param B : The obstacle producing the repulsive effect.
|
||||
// @return The velocity increment caused by the repulsive effect from obstacle B on alpha during one
|
||||
// simulation time step.
|
||||
//
|
||||
Vector2d obstacle_repulsion_dt(const Pedestrian &alpha, const Obstacle &B);
|
||||
+1093
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#include "constants.hpp"
|
||||
#include "vector2d.hpp"
|
||||
|
||||
// Needed for visual simulation, in order to distinguish two groups of pedestrians:
|
||||
// - White pedestrians move from left to right
|
||||
// - Black pedestrians move from right to left
|
||||
enum Color { WHITE, BLACK};
|
||||
|
||||
struct Pedestrian {
|
||||
|
||||
Color color;
|
||||
|
||||
// $\vec{v}_{\alpha}(t)$
|
||||
Vector2d curr_vel; // v_alpha (actual, ≤ v_max)
|
||||
|
||||
// $\vec{w}_{\alpha}$
|
||||
Vector2d w; // w_alpha (preferred, integrates force)
|
||||
|
||||
// $\vec{r}_\alpha(t)$
|
||||
Vector2d curr_pos;
|
||||
|
||||
// $\vec{e}_{\alpha}(t)$
|
||||
Vector2d e; // desired direction vector
|
||||
|
||||
// $v_{\alpha}^{max} = 1.3 v^{0}_{\alpha}$
|
||||
double v_max;
|
||||
|
||||
// $v_\alpha^0$
|
||||
double desired_v0;
|
||||
|
||||
// $\vec{r}^0_\alpha$
|
||||
Vector2d destination;
|
||||
// $s_\beta^2 = (v_\beta \Delta t)^2$
|
||||
double s_b_sq;
|
||||
// $s_\beta \vec{e}_\beta$
|
||||
Vector2d s_b_e;
|
||||
|
||||
// Default constructor: initializes a pedestrian with color WHITE and all vector/scalar fields set to zero.
|
||||
Pedestrian() : color(WHITE), curr_vel(0.0, 0.0), w(0.0, 0.0), curr_pos(0.0, 0.0), e(0.0, 0.0), v_max(0.0), desired_v0(0.0), destination(0.0, 0.0), s_b_sq(0.0), s_b_e(0.0, 0.0) {}
|
||||
|
||||
// Constructs a pedestrian with the given initial state and precomputes the
|
||||
// quantities used in the pedestrian-pedestrian repulsion term.
|
||||
//
|
||||
// The preferred velocity w is initialized to the current velocity c_v. The
|
||||
// cached quantities s_b_sq and s_b_e correspond to the predicted step of this
|
||||
// pedestrian over $\Delta t$:
|
||||
//
|
||||
// s_b = ||c_v|| * dt
|
||||
// s_b_sq = s_b^2
|
||||
// s_b_e = e * s_b
|
||||
//
|
||||
// These values are used when another pedestrian computes the elliptical
|
||||
// interaction term involving this pedestrian.
|
||||
//
|
||||
// @param clr The display/color category of the pedestrian.
|
||||
// @param c_v The initial current velocity.
|
||||
// @param c_p The initial current position.
|
||||
// @param e The initial desired direction of motion.
|
||||
// @param v_max The maximum speed that the pedestrian can reach.
|
||||
// @param desired_v0 The desired walking speed.
|
||||
// @param d The pedestrian's target destination point.
|
||||
//
|
||||
Pedestrian(Color clr, Vector2d c_v, Vector2d c_p, Vector2d e, double v_max, double desired_v0, Vector2d d) : color(clr), curr_vel(c_v), w(c_v), curr_pos(c_p), e(e), v_max(v_max), desired_v0(desired_v0), destination(d), s_b_sq(c_v.dot(c_v) * delta_t_sq), s_b_e(e * c_v.norm() * delta_t) {}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "constants.hpp"
|
||||
|
||||
struct Pedestrian {
|
||||
|
||||
int color;
|
||||
|
||||
double curr_vel_x;
|
||||
double curr_vel_y;
|
||||
|
||||
double w_x;
|
||||
double w_y;
|
||||
|
||||
double curr_pos_x;
|
||||
double curr_pos_y;
|
||||
|
||||
double e_x;
|
||||
double e_y;
|
||||
|
||||
double v_max;
|
||||
|
||||
double desired_v0;
|
||||
|
||||
double destination_x;
|
||||
double destination_y;
|
||||
|
||||
double s_b_sq;
|
||||
double s_b_e_x;
|
||||
double s_b_e_y;
|
||||
|
||||
Pedestrian() : color(0), curr_vel_x(0.0), curr_vel_y(0), w_x(0.0), w_y(0.0), curr_pos_x(0.0), curr_pos_y(0.0), e_x(0.0), e_y(0.0), v_max(0.0), desired_v0(0.0), destination_x(0.0), destination_y(0.0), s_b_sq(0.0), s_b_e_x(0.0), s_b_e_y(0.0) {}
|
||||
|
||||
Pedestrian(int clr, double c_v_x, double c_v_y, double c_p_x, double c_p_y, double e_x, double e_y, double v_max, double desired_v0, double d_x, double d_y)
|
||||
: color(clr), curr_vel_x(c_v_x), curr_vel_y(c_v_y), w_x(c_v_x), w_y(c_v_y), curr_pos_x(c_p_x), curr_pos_y(c_p_y), e_x(e_x), e_y(e_y), v_max(v_max), desired_v0(desired_v0), destination_x(d_x), destination_y(d_y), s_b_sq((c_v_x * c_v_x + c_v_y * c_v_y) * delta_t_sq), s_b_e_x(e_x * (sqrt(c_v_x * c_v_x + c_v_y * c_v_y)) * delta_t), s_b_e_y(e_y * (sqrt(c_v_x * c_v_x + c_v_y * c_v_y)) * delta_t) {}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "board.hpp"
|
||||
#include "pedestrian.hpp"
|
||||
|
||||
// Initializes the pedestrians used in the simulation.
|
||||
//
|
||||
// The returned array contains n_p pedestrians split into two groups:
|
||||
// one group walking from left to right and one group walking from right to left.
|
||||
// Pedestrian positions, desired speeds, destinations, and initial directions are
|
||||
// initialized according to the simulation setup.
|
||||
//
|
||||
// @param n_p : Number of pedestrians to initialize.
|
||||
// @return Pointer to a dynamically allocated array of pedestrians.
|
||||
Pedestrian *init_pedestrians(int n_p);
|
||||
|
||||
// Initializes a simulation board with no obstacles inside.
|
||||
//
|
||||
// @return Initialized Board instance.
|
||||
Board init_board_without_obstacles();
|
||||
|
||||
// Runs the social force model with n_p pedestrians for n_iter iterations,
|
||||
// i.e., n_iter * dt simulated seconds.
|
||||
// If dump_path is not nullptr, the simulation states are written to that CSV
|
||||
// file, which can be used to generate a visualization video. If dump_path is
|
||||
// nullptr, no output file is generated.
|
||||
//
|
||||
// @param pedestrians : Array of pedestrians to simulate. The array is updated in place.
|
||||
// @param board : Board containing the simulation dimensions and obstacles.
|
||||
// @param n_p : Number of pedestrians.
|
||||
// @param n_iter : Number of simulation iterations.
|
||||
// @param dump_path : Optional path to the CSV output file.
|
||||
// @return 0 on success.
|
||||
int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, const char *dump_path);
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "vector2d.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// default tolerance value
|
||||
constexpr double tolerance = 1e-9;
|
||||
|
||||
// Compare two Vector2d component-wise, with tolerance, and assert if difference between expected and obtained value is below tolerance
|
||||
inline ::testing::AssertionResult Vec2Near(const Vector2d &a, const Vector2d &b, double tol = tolerance) {
|
||||
if (std::fabs(a.x - b.x) <= tol && std::fabs(a.y - b.y) <= tol) {
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
return ::testing::AssertionFailure() << "expected (" << b.x << ", " << b.y << "), got (" << a.x << ", " << a.y << "), diff (" << (a.x - b.x) << ", " << (a.y - b.y) << ")" << ", exceeds tolerance : " << tol;
|
||||
}
|
||||
|
||||
#define EXPECT_VEC2_NEAR(actual, expected) EXPECT_TRUE(Vec2Near((actual), (expected)))
|
||||
|
||||
#define EXPECT_VEC2_NEAR_TOL(actual, expected, tol) EXPECT_TRUE(Vec2Near((actual), (expected), (tol)))
|
||||
@@ -0,0 +1,83 @@
|
||||
/* ==================== GNU C and possibly other UNIX compilers ===================== */
|
||||
#ifndef _WIN32
|
||||
|
||||
#if defined(__GNUC__) || defined(__linux__)
|
||||
#define VOLATILE __volatile__
|
||||
#define ASM __asm__
|
||||
#else
|
||||
/* if we're neither compiling with gcc or under linux, we can hope
|
||||
* the following lines work, they probably won't */
|
||||
#define ASM asm
|
||||
#define VOLATILE
|
||||
#endif
|
||||
|
||||
#define myInt64 unsigned long long
|
||||
#define INT32 unsigned int
|
||||
|
||||
/* ======================== WIN32 ======================= */
|
||||
#else
|
||||
|
||||
#define myInt64 signed __int64
|
||||
#define INT32 unsigned __int32
|
||||
|
||||
#endif
|
||||
|
||||
/* This is the RDTSC timer.
|
||||
* RDTSC is an instruction on several Intel and compatible CPUs that Reads the
|
||||
* Time Stamp Counter. The Intel manuals contain more information.
|
||||
*/
|
||||
|
||||
#define COUNTER_LO(a) ((a).int32.lo)
|
||||
#define COUNTER_HI(a) ((a).int32.hi)
|
||||
#define COUNTER_VAL(a) ((a).int64)
|
||||
|
||||
#define COUNTER(a) ((unsigned long long)COUNTER_VAL(a))
|
||||
|
||||
#define COUNTER_DIFF(a, b) (COUNTER(a) - COUNTER(b))
|
||||
|
||||
/* ==================== GNU C and possibly other UNIX compilers ===================== */
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef union {
|
||||
myInt64 int64;
|
||||
struct {
|
||||
INT32 lo, hi;
|
||||
} int32;
|
||||
} tsc_counter;
|
||||
|
||||
#define RDTSC(cpu_c) ASM VOLATILE("rdtsc" : "=a"((cpu_c).int32.lo), "=d"((cpu_c).int32.hi))
|
||||
#define CPUID() ASM VOLATILE("cpuid" : : "a"(0) : "bx", "cx", "dx")
|
||||
|
||||
/* ======================== WIN32 ======================= */
|
||||
#else
|
||||
|
||||
typedef union {
|
||||
myInt64 int64;
|
||||
struct {
|
||||
INT32 lo, hi;
|
||||
} int32;
|
||||
} tsc_counter;
|
||||
|
||||
#define RDTSC(cpu_c) {__asm rdtsc __asm mov(cpu_c).int32.lo, eax __asm mov(cpu_c).int32.hi, edx}
|
||||
|
||||
#define CPUID() {__asm mov eax, 0 __asm cpuid}
|
||||
|
||||
#endif
|
||||
|
||||
static void init_tsc() {
|
||||
; // no need to initialize anything for x86
|
||||
}
|
||||
|
||||
static myInt64 start_tsc(void) {
|
||||
tsc_counter start;
|
||||
CPUID();
|
||||
RDTSC(start);
|
||||
return COUNTER_VAL(start);
|
||||
}
|
||||
|
||||
static myInt64 stop_tsc(myInt64 start) {
|
||||
tsc_counter end;
|
||||
RDTSC(end);
|
||||
CPUID();
|
||||
return COUNTER_VAL(end) - start;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
// This function exactly tracks the flop count for each function
|
||||
// Usage
|
||||
// compile, e.g.:
|
||||
// make run-bench FLOPCOUNT=1 N_P=60 N_ITER=4000
|
||||
// if not compiled with FLOPCOUNT all associated function are written as ((void)0) and removed when using -O3 flag
|
||||
// In code:
|
||||
// FLOP_RECORD(flop_counter::<FUNC_NAME>, int add, int mult, int div, int sqrt, int exp)
|
||||
// <FUNC_NAME> see FunctionId in util.hpp
|
||||
// Print out metrics:
|
||||
// flop_counter::report();
|
||||
// flop_counter::report_csv();
|
||||
// Additonal remarks:
|
||||
// make sure to call flop_counter::reset(); after the warmup phase, because else counting flops double
|
||||
// make sure to import util.hpp #include "util.hpp"
|
||||
|
||||
// get the cycles count per flop
|
||||
#include "constants.hpp" // cost_add, cost_mult, cost_div, cost_sqrt, cost_exp
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#ifndef FLOPCOUNT
|
||||
#define FLOPCOUNT 0
|
||||
#endif
|
||||
|
||||
namespace flop_counter {
|
||||
|
||||
// defined functions, add new one if needed
|
||||
// create enumeration, which must be in sync with kFunctionNames
|
||||
enum FunctionId : int {
|
||||
FN_W,
|
||||
FN_ACCELERATION,
|
||||
FN_PEDESTRIAN_REPULSION,
|
||||
FN_OBSTACLE_REPULSION,
|
||||
FN_NEAREST_OBSTACLE_POINT,
|
||||
FN_UPDATE,
|
||||
FN_OTHER,
|
||||
FN_COUNT
|
||||
};
|
||||
|
||||
// track the flop count for each function separately
|
||||
// add more functions, do not mix up the order
|
||||
inline constexpr std::array<const char *, FN_COUNT> kFunctionNames = {
|
||||
"w",
|
||||
"acceleration_term_dt",
|
||||
"pedestrian_repulsion_dt",
|
||||
"obstacle_repulsion_dt",
|
||||
"find_nearest_obstacle_point",
|
||||
"update_pass",
|
||||
"other",
|
||||
};
|
||||
|
||||
#if FLOPCOUNT
|
||||
|
||||
// for each function store add, mult, div, sqrt, exp
|
||||
inline std::uint64_t counters[FN_COUNT][5]{};
|
||||
|
||||
// update
|
||||
inline void record(FunctionId fn, std::uint64_t add, std::uint64_t mult,
|
||||
std::uint64_t div, std::uint64_t sqrt_n,
|
||||
std::uint64_t exp_n) {
|
||||
counters[fn][0] += add;
|
||||
counters[fn][1] += mult;
|
||||
counters[fn][2] += div;
|
||||
counters[fn][3] += sqrt_n;
|
||||
counters[fn][4] += exp_n;
|
||||
}
|
||||
|
||||
// set all metrics to 0
|
||||
inline void reset() {
|
||||
for (int f = 0; f < FN_COUNT; ++f)
|
||||
for (int o = 0; o < 5; ++o)
|
||||
counters[f][o] = 0;
|
||||
}
|
||||
|
||||
inline void report() {
|
||||
std::printf("\n=== flop count ===\n");
|
||||
std::printf("%-30s %12s %12s %12s %12s %12s %16s\n",
|
||||
"function", "add", "mult", "div", "sqrt", "exp", "per function");
|
||||
long double total = 0;
|
||||
for (int f = 0; f < FN_COUNT; ++f) {
|
||||
auto a = counters[f][0], m = counters[f][1], d = counters[f][2],
|
||||
s = counters[f][3], e = counters[f][4];
|
||||
long double w = a * (long double)cost_add + m * (long double)cost_mult
|
||||
+ d * (long double)cost_div + s * (long double)cost_sqrt
|
||||
+ e * (long double)cost_exp;
|
||||
total += w;
|
||||
if ((a | m | d | s | e) == 0) continue;
|
||||
std::printf("%-30s %12llu %12llu %12llu %12llu %12llu %16.2Lf\n",
|
||||
kFunctionNames[f],
|
||||
(unsigned long long)a, (unsigned long long)m,
|
||||
(unsigned long long)d, (unsigned long long)s,
|
||||
(unsigned long long)e, w);
|
||||
}
|
||||
std::printf("%-30s %12s %12s %12s %12s %12s %16.2Lf\n",
|
||||
"TOTAL", "", "", "", "", "", total);
|
||||
}
|
||||
|
||||
#define FLOP_RECORD(fn, a, m, d, s, e) \
|
||||
::flop_counter::record((fn), (a), (m), (d), (s), (e))
|
||||
|
||||
#else // FLOPCOUNT == 0 -> no-op, removed by -O3
|
||||
|
||||
inline void record(FunctionId, std::uint64_t, std::uint64_t, std::uint64_t,
|
||||
std::uint64_t, std::uint64_t) {}
|
||||
inline void reset() {}
|
||||
inline void report() {}
|
||||
|
||||
#define FLOP_RECORD(fn, a, m, d, s, e) ((void)0)
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace flop_counter
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include <math.h>
|
||||
|
||||
struct Vector2d {
|
||||
double x, y;
|
||||
Vector2d(double a, double b) : x(a), y(b) {}
|
||||
Vector2d() : x(.0), y(.0) {}
|
||||
Vector2d operator+(Vector2d v) const { return Vector2d(v.x + x, v.y + y); }
|
||||
Vector2d operator-(Vector2d v) const { return Vector2d(x - v.x, y - v.y); }
|
||||
Vector2d operator-(double a) const { return Vector2d(x - a, y - a); }
|
||||
Vector2d operator+(double a) const { return Vector2d(x + a, y + a); }
|
||||
Vector2d operator/(double a) const { return Vector2d(x / a, y / a); }
|
||||
Vector2d operator*(double a) const { return Vector2d(x * a, y * a); }
|
||||
Vector2d operator+=(const Vector2d &v) {
|
||||
*this = *this + v;
|
||||
return *this;
|
||||
}
|
||||
Vector2d operator-=(const Vector2d &v) {
|
||||
*this = *this - v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector2d reverse_sign() { return Vector2d(-x, -y); }
|
||||
|
||||
// # 1 ADD, 2 MULTs, 1 SQRT
|
||||
double norm() { return sqrt(x * x + y * y); }
|
||||
|
||||
// # 1 ADD, 2 MULTs
|
||||
double dot(Vector2d v) { return x * v.x + y * v.y; }
|
||||
void reset() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user