Skip to content

Conversation

@jonathanpoelen
Copy link

@jonathanpoelen jonathanpoelen commented Jun 20, 2023

I put in bulk the benchmarks and tests that can be found in each commit (issue #77)

(result of /usr/bin/time --format='%Es - %MK' $compiler ...)

mp_transform_if

compiler gcc-12 clang-15
before 0:00.13s - 60432K 0:00.16s - 100956K
after 0:00.11s - 47300K 0:00.16s - 100484K
template<class T> using p = mp_bool<T::value & 1>;
template<class T> using f = mp_size_t<T::value + 1>;
template<class I> using test = mp_transform_if<p, f, mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<50>>;

mp_filter

compiler gcc-12 clang-15
before 0:00.16s - 72460K 0:00.16s - 102068K
after 0:00.14s - 61884K 0:00.16s - 101828K
template<class T> using p = mp_bool<T::value & 1>;
template<class I> using test = mp_filter<p, mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<50>>;

mp_drop

compiler gcc-12 clang-15
before 0:00.48s - 192464K 0:00.48s - 154480K
after 0:00.43s - 172472K 0:00.46s - 150404K
template<class L> struct f { template<class I> using g = mp_drop<L, I>; };
template<class I, class L = mp_iota<I>> using test = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<50>>;

mp_sort

compiler gcc-12 clang-15
before 0:00.46s - 198848K 0:00.49s - 132632K
after 0:00.42s - 183384K 0:00.48s - 131748K
template<class I> using test = mp_sort<mp_iota<I>, mp_less>;

using r1 = mp_transform<test, mp_iota_c<25>>;

mp_replace_at

compiler gcc-12 clang-15
before 0:00.34s - 134428K 0:00.33s - 124720K
after 0:00.29s - 116920K 0:00.32s - 122568K
template<class I> using f = mp_replace_at<mp_iota<I>, I, void>;
template<class I> using test = mp_transform<f, mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<50>>;

mp_power_set

compiler gcc-12 clang-15
before 0:01.35s - 538732K 0:00.65s - 203924K
after 0:01.02s - 396032K 0:00.65s - 203080K
template<class I> using test = mp_power_set<mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<15>>;

mp_map_find

compiler gcc-12 clang-15
before 0:00.29s - 128600K 0:00.25s - 120604K
after 0:00.22s - 99908K 0:00.23s - 116084K
template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_find<M, I>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<50>>;

mp_map_update

compiler gcc-12 clang-15
before 0:00.73s - 270224K 0:00.54s - 156112K
after 0:00.19s - 85004K 0:00.29s - 119232K
template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_update<M, mp_list<I>, mp_list>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<20>>;

mp_map_erase

compiler gcc-12 clang-15
before 0:00.52s - 197128K 0:00.44s - 140780K
after 0:00.47s - 183968K 0:00.43s - 139336K
template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_erase<M, I>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<30>>;

mp_map_replace

compiler gcc-12 clang-15
before 0:00.46s - 187160K 0:00.38s - 129104K
after 0:00.21s - 80236K 0:00.33s - 123644K
template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_replace<M, mp_list<I, I>>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<30>>;

@jonathanpoelen jonathanpoelen changed the title Improve compilation speed by taking advantage of memoization #77 Improve compilation speed by taking advantage of memoization Jun 20, 2023
@jonathanpoelen
Copy link
Author

@pdimov would you be able to take a look, please?

@pdimov
Copy link
Member

pdimov commented Nov 2, 2025

If you use fn as the name of the inner alias, instead of _f et al, these helpers will become quoted metafunctions and you'll be able to use the _q variants of the algorithms instead of spelling the ::template _f.

…emoization)

compiler |       gcc-12      |      clang-15
before   | 0:00.13s - 60432K | 0:00.16s - 100956K
after    | 0:00.11s - 47300K | 0:00.16s - 100484K

```cpp
using namespace boost::mp11;

template<class T> using p = mp_bool<T::value & 1>;
template<class T> using f = mp_size_t<T::value + 1>;
template<class I> using test = mp_transform_if<p, f, mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<50>>;
```
…tion)

compiler |       gcc-12      |      clang-15
before   | 0:00.16s - 72460K | 0:00.16s - 102068K
after    | 0:00.14s - 61884K | 0:00.16s - 101828K

```cpp
using namespace boost::mp11;

template<class T> using p = mp_bool<T::value & 1>;
template<class I> using test = mp_filter<p, mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<50>>;
```
compiler |       gcc-12       |      clang-15
before   | 0:00.48s - 192464K | 0:00.48s - 154480K
after    | 0:00.43s - 172472K | 0:00.46s - 150404K

```cpp
template<class L> struct f { template<class I> using g = mp_drop<L, I>; };
template<class I, class L = mp_iota<I>> using test = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<50>>;
```
compiler |       gcc-12       |      clang-15
before   | 0:00.46s - 198848K | 0:00.49s - 132632K
after    | 0:00.42s - 183384K | 0:00.48s - 131748K

```cpp
using namespace boost::mp11;

template<class I> using test = mp_sort<mp_iota<I>, mp_less>;

using r1 = mp_transform<test, mp_iota_c<25>>;
```
…oization)

compiler |       gcc-12       |      clang-15
before   | 0:00.34s - 134428K | 0:00.33s - 124720K
after    | 0:00.29s - 116920K | 0:00.32s - 122568K

```cpp
using namespace boost::mp11;

template<class I> using f = mp_replace_at<mp_iota<I>, I, void>;
template<class I> using test = mp_transform<f, mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<50>>;
```
…ization)

compiler |       gcc-12       |      clang-15
before   | 0:01.35s - 538732K | 0:00.65s - 203924K
after    | 0:01.02s - 396032K | 0:00.65s - 203080K

```cpp
using namespace boost::mp11;

template<class I> using test = mp_power_set<mp_iota<I>>;

using r1 = mp_transform<test, mp_iota_c<15>>;
```
…zation)

compiler |       gcc-12       |      clang-15
before   | 0:00.29s - 128600K | 0:00.25s - 120604K
after    | 0:00.22s - 99908K  | 0:00.23s - 116084K

```cpp
using namespace boost::mp11;

template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_find<M, I>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<50>>;
```
…oization)

compiler |       gcc-12       |      clang-15
before   | 0:00.73s - 270224K | 0:00.54s - 156112K
after    | 0:00.19s - 85004K  | 0:00.29s - 119232K

```cpp
using namespace boost::mp11;

template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_update<M, mp_list<I>, mp_list>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<20>>;
```
…ization)

compiler |       gcc-12       |      clang-15
before   | 0:00.52s - 197128K | 0:00.44s - 140780K
after    | 0:00.47s - 183968K | 0:00.43s - 139336K

```cpp
using namespace boost::mp11;

template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_erase<M, I>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<30>>;
```
compiler |       gcc-12       |      clang-15
before   | 0:00.46s - 187160K | 0:00.38s - 129104K
after    | 0:00.21s - 80236K  | 0:00.33s - 123644K

```cpp
using namespace boost::mp11;

template<class L, class M = mp_transform<mp_list, L>>
struct f { template<class I> using g = mp_map_replace<M, mp_list<I, I>>; };

template<class I, class L = mp_iota<I>> using test
  = mp_transform<f<L>::template g, L>;

using r1 = mp_transform<test, mp_iota_c<30>>;
```
@pdimov
Copy link
Member

pdimov commented Nov 3, 2025

This looks good to me. I can only wonder why I failed to look at it two years ago when you submitted it originally; it probably came in an inopportune time when I was too busy.

I see a couple more things. It looks like you started to also optimize mp_map_replace_impl by moving the msvc workaround into an ifdef, but then didn't extract _f into a helper template.

Also, in the two cases where the _impl class is reduced to just having a single using type = ... (mp_transform_if_impl and mp_map_erase_impl), you can just remove the _impl class altogether and move the ... part into the primary alias.

The 1.90 beta cutoff is the day after tomorrow, so I won't be able to merge this now, but to make sure I don't drop the ball again (sorry), please remind me after 1.90 is released.

And thank you for this work.

@jonathanpoelen
Copy link
Author

I see a couple more things. It looks like you started to also optimize mp_map_replace_impl by moving the msvc workaround into an ifdef, but then didn't extract _f into a helper template.

I went back to msvc because it wasn't working: 87719f6. However, after two years, the logs are no longer available.

Also, in the two cases where the _impl class is reduced to just having a single using type = ... (mp_transform_if_impl and mp_map_erase_impl), you can just remove the _impl class altogether and move the ... part into the primary alias.

Done.

The 1.90 beta cutoff is the day after tomorrow, so I won't be able to merge this now, but to make sure I don't drop the ball again (sorry), please remind me after 1.90 is released.

I will try to remember :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants