parallel101 / course

高性能并行编程与优化 - 课件
https://space.bilibili.com/263032155
Other
3.62k stars 532 forks source link

关于第十课---多层嵌套稀疏数据结构代码---BUG #10

Open GeLee-Q opened 2 years ago

GeLee-Q commented 2 years ago

实验环境:

# ubuntu20.04
# linux 内核: 5.13.0-48-generic
# gcc 11.0

Q1 :10/03/01.cpp 编译出错

/sparse_data_struct/00.cpp: In instantiation of ‘static void RootGrid<T, Layout>::_write(Node&, int, int, T) [with Node = const HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >; T = char; Layout = HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >]’:
/sparse_data_struct/00.cpp:158:22:   required from ‘void RootGrid<T, Layout>::write(int, int, T) const [with T = char; Layout = HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >]’
/sparse_data_struct/00.cpp:197:17:   required from here
/sparse_data_struct/00.cpp:152:37: 错误: passing ‘const HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >’ as ‘this’ argument discards qualifiers [-fpermissive]
  152 |             auto *child = node.touch(x >> node.bitShift, y >> node.bitShift);
      |                           ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/sparse_data_struct/00.cpp:87:11: 附注:   在调用‘Node* HashBlock<Node>::touch(int, int) [with Node = PointerBlock<11, DenseBlock<8, PlaceData<char> > >]’时
   87 |     Node *touch(int x, int y) {
      |           ^~~~~
/sparse_data_struct/00.cpp: In instantiation of ‘void DenseBlock<Bshift, Node>::foreach(const Func&) [with Func = RootGrid<char, HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > > >::_foreach<DenseBlock<8, PlaceData<char> >, main()::<lambda(int, int, char&)> >(DenseBlock<8, PlaceData<char> >&, int, int, const main()::<lambda(int, int, char&)>&)::<lambda(int, int, auto:1*)>; int Bshift = 8; Node = PlaceData<char>]’:
/sparse_data_struct/00.cpp:170:32:   required from ‘static void RootGrid<T, Layout>::_foreach(Node&, int, int, const Func&) [with Node = DenseBlock<8, PlaceData<char> >; Func = main()::<lambda(int, int, char&)>; T = char; Layout = HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >]’
/sparse_data_struct/00.cpp:171:25:   required from ‘RootGrid<char, HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > > >::_foreach<PointerBlock<11, DenseBlock<8, PlaceData<char> > >, main()::<lambda(int, int, char&)> >(PointerBlock<11, DenseBlock<8, PlaceData<char> > >&, int, int, const main()::<lambda(int, int, char&)>&)::<lambda(int, int, auto:1*)> [with auto:1 = DenseBlock<8, PlaceData<char> >]’
/sparse_data_struct/00.cpp:60:25:   required from ‘void PointerBlock<Bshift, Node>::foreach(const Func&) [with Func = RootGrid<char, HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > > >::_foreach<PointerBlock<11, DenseBlock<8, PlaceData<char> > >, main()::<lambda(int, int, char&)> >(PointerBlock<11, DenseBlock<8, PlaceData<char> > >&, int, int, const main()::<lambda(int, int, char&)>&)::<lambda(int, int, auto:1*)>; int Bshift = 11; Node = DenseBlock<8, PlaceData<char> >]’
/sparse_data_struct/00.cpp:170:32:   required from ‘static void RootGrid<T, Layout>::_foreach(Node&, int, int, const Func&) [with Node = PointerBlock<11, DenseBlock<8, PlaceData<char> > >; Func = main()::<lambda(int, int, char&)>; T = char; Layout = HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >]’
/sparse_data_struct/00.cpp:171:25:   required from ‘RootGrid<char, HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > > >::_foreach<HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >, main()::<lambda(int, int, char&)> >(HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >&, int, int, const main()::<lambda(int, int, char&)>&)::<lambda(int, int, auto:1*)> [with auto:1 = PointerBlock<11, DenseBlock<8, PlaceData<char> > >]’
/sparse_data_struct/00.cpp:102:17:   required from ‘void HashBlock<Node>::foreach(const Func&) [with Func = RootGrid<char, HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > > >::_foreach<HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >, main()::<lambda(int, int, char&)> >(HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >&, int, int, const main()::<lambda(int, int, char&)>&)::<lambda(int, int, auto:1*)>; Node = PointerBlock<11, DenseBlock<8, PlaceData<char> > >]’
/sparse_data_struct/00.cpp:170:32:   required from ‘static void RootGrid<T, Layout>::_foreach(Node&, int, int, const Func&) [with Node = HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >; Func = main()::<lambda(int, int, char&)>; T = char; Layout = HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >]’
/sparse_data_struct/00.cpp:178:17:   required from ‘void RootGrid<T, Layout>::foreach(const Func&) [with Func = main()::<lambda(int, int, char&)>; T = char; Layout = HashBlock<PointerBlock<11, DenseBlock<8, PlaceData<char> > > >]’
/sparse_data_struct/00.cpp:201:15:   required from here
/sparse_data_struct/00.cpp:27:28: 错误: no match for ‘operator*’ (operand type is ‘PlaceData<char>’)
   27 |                 func(x, y, *m_data[x][y]);
      |               

修改后 DenseBlock & HashBlock后可以编译跑通:

template <int Bshift, class Node>
struct DenseBlock {
    static constexpr bool isPlace = false;
    static constexpr bool bitShift = Bshift;

    static constexpr int B = 1 << Bshift;
    static constexpr int Bmask = B - 1;

    Node m_data[B][B];

    Node *fetch(int x, int y) const {
        return &m_data[x & Bmask][y & Bmask];
    }

    Node *touch(int x, int y) {
        return &m_data[x & Bmask][y & Bmask];
    }

    // change_00  : * -> &
    template <class Func>
    void foreach(Func const &func) {
        for (int x = 0; x < B; x++) {
            for (int y = 0; y < B; y++) {
                func(x, y, &m_data[x][y]);
            }
        }
    }
};
template <class Node>
struct HashBlock {
    static constexpr bool isPlace = false;
    static constexpr bool bitShift = 0;

    struct MyHash {
        std::size_t operator()(std::tuple<int, int> const &key) const {
            auto const &[x, y] = key;
            return (x * 2718281828) ^ (y * 3141592653);
        }
    };

    //change_01 <Node> -> std::unique_ptr<Node>
    std::unordered_map<std::tuple<int, int>, std::unique_ptr<Node>, MyHash> m_data;

    // change_02  : it->second.get();
    Node *fetch(int x, int y) const {
        auto it = m_data.find(std::make_tuple(x, y));
        if (it == m_data.end())
            return nullptr;
        return it->second.get();
    }

    Node *touch(int x, int y) {
        auto it = m_data.find(std::make_tuple(x, y));
        if (it == m_data.end()) {
            std::unique_ptr<Node> ptr = std::make_unique<Node>();
            auto rawptr = ptr.get();
            m_data.emplace(std::make_tuple(x, y), std::move(ptr));
            return rawptr;
        }
        return it->second.get();
    }

    //change_03 &block -> unique_node.get()  (unique_Node = block)
    template <class Func>
    void foreach(Func const &func) {
        for (auto &[key, unique_Node]: m_data) {
            auto &[x, y] = key;
            func(x, y, unique_Node.get());
        }
    }
};

58YFUS9X$98U3W%8M_@%2BX

在运行时遇到内存不断增加的状况。 当N 为(2 * 2) 时,使用valgrind 和 massif-visualizer 查看内存,构造的空间足足有96M, 可能是代码改错了,还请小彭老师看看。

Q2 10/04/06.cpp 运行时内存爆炸

为了方便在我自己平台的跑起来,将main中的foreach改成了和之前的代码一样。

    int count = 0;
    a->foreach([&] (int x, int y, char &value) {
        if (value != 0) {
            count++;
        }
    });
    printf("count: %d\n", count);

情况 1 : N(512 * 512)

结果:运行内存64g全部跑满,最后core dump。

这个可视化的图是在代码运行占到内存一半的时候,ctrl + c 后得到的信息图。 R}}X)1RI0EU$H{K5OJRDAOX

情况 2 : N(32 * 32 )

count: 109
main: 14.5131s

内存可视化信息如下: 2U3TY{BVCZZ8W@V1_V)_KAY

最后想问一下小彭老师,这个代码没有给错吗,为什么会不停的申请内存导致最后完全不够用呢。