]> git.sesse.net Git - casparcg/blob - modules/decklink/util/decklink_allocator.h
* Created custom decklink allocator for reducing memory footprint.
[casparcg] / modules / decklink / util / decklink_allocator.h
1 /*
2 * Copyright 2013 Sveriges Television AB http://casparcg.com/
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #pragma once
23
24 #include <memory>
25 #include <string>
26 #include <vector>
27 #include <stack>
28 #include <map>
29
30 #include <boost/thread.hpp>
31
32 #include <tbb/concurrent_queue.h>
33 #include <tbb/concurrent_unordered_map.h>
34 #include <tbb/atomic.h>
35
36 #include <common/utility/assert.h>
37 //#include <common/memory/page_locked_allocator.h>
38 #include <common/exception/win32_exception.h>
39
40 #include "../interop/DeckLinkAPI_h.h"
41
42 namespace caspar { namespace decklink {
43
44 class thread_safe_decklink_allocator : public IDeckLinkMemoryAllocator
45 {
46         typedef std::shared_ptr<
47                         std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>>> buffer;
48
49         std::wstring print_;
50         tbb::concurrent_unordered_map<size_t, tbb::concurrent_queue<void*>> free_;
51         tbb::concurrent_unordered_map<void*, buffer> buffers_;
52         tbb::atomic<size_t> total_allocated_;
53         tbb::atomic<int64_t> total_calls_;
54 public:
55         thread_safe_decklink_allocator(const std::wstring& print)
56                 : print_(print)
57         {
58                 total_allocated_ = 0;
59                 total_calls_ = 0;
60         }
61
62         ~thread_safe_decklink_allocator()
63         {
64                 CASPAR_LOG(debug)
65                         << print_
66                         << L" allocated a total of " << total_allocated_ << L" bytes"
67                         << L" and was called " << total_calls_ << L" times"
68                         << L" during playout";
69         }
70
71         virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(
72                         unsigned long buffer_size, void** allocated_buffer)
73         {
74                 win32_exception::ensure_handler_installed_for_thread(
75                                 "decklink-allocator");
76
77                 try
78                 {
79                         *allocated_buffer = allocate_buffer(buffer_size);
80                 }
81                 catch (const std::bad_alloc&)
82                 {
83                         CASPAR_LOG_CURRENT_EXCEPTION();
84
85                         return E_OUTOFMEMORY;
86                 }
87
88                 return S_OK;
89         }
90
91         void* allocate_buffer(unsigned long buffer_size)
92         {
93                 ++total_calls_;
94                 void* result;
95
96                 if (!free_[buffer_size].try_pop(result))
97                 {
98                         auto buf = std::make_shared<std::vector<uint8_t,
99                                         tbb::cache_aligned_allocator<uint8_t>>>(buffer_size);
100                         result = buf->data();
101                         buffers_.insert(std::make_pair(result, buf));
102
103                         total_allocated_ += buffer_size;
104
105                         CASPAR_LOG(debug)
106                                         << print_
107                                         << L" allocated buffer of size: " << buffer_size
108                                         << L" for a total of " << total_allocated_;
109                 }
110
111                 return result;
112         }
113
114         virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* b)
115         {
116                 win32_exception::ensure_handler_installed_for_thread(
117                                 "decklink-allocator");
118
119                 try
120                 {
121                         release_buffer(b);
122                 }
123                 catch (const std::bad_alloc&)
124                 {
125                         CASPAR_LOG_CURRENT_EXCEPTION();
126                 }
127
128                 return S_OK;
129         }
130
131         void release_buffer(void* b)
132         {
133                 auto buf = buffers_[b];
134
135                 CASPAR_VERIFY(buf);
136
137                 free_[buf->size()].push(b);
138         }
139
140         virtual HRESULT STDMETHODCALLTYPE Commit()
141         {
142                 return S_OK;
143         }
144
145         virtual HRESULT STDMETHODCALLTYPE Decommit()
146         {
147                 return S_OK;
148         }
149
150         STDMETHOD (QueryInterface(REFIID, LPVOID*))     {return E_NOINTERFACE;}
151         STDMETHOD_(ULONG, AddRef())                                     {return 1;}
152         STDMETHOD_(ULONG, Release())                            {return 1;}
153 };
154
155 }}