| 39 | namespace tensorflow { |
| 40 | |
| 41 | class Stack : public ResourceBase { |
| 42 | public: |
| 43 | static std::atomic<int64> stack_counter; |
| 44 | |
| 45 | struct TensorAndAllocation { |
| 46 | Tensor tensor; |
| 47 | AllocatorAttributes alloc_attrs; |
| 48 | bool swapped_to_cpu; |
| 49 | }; |
| 50 | |
| 51 | Stack(const DataType& elem_type, const string& stack_name, int max_size) |
| 52 | : elem_type_(elem_type), |
| 53 | stack_name_(stack_name), |
| 54 | max_size_(max_size), |
| 55 | closed_(false) {} |
| 56 | |
| 57 | Status Push(const TensorAndAllocation& value) { |
| 58 | mutex_lock l(mu_); |
| 59 | TF_RETURN_IF_ERROR(CheckNotClosed()); |
| 60 | if (max_size_ >= 0 && stack_.size() >= max_size_) { |
| 61 | return errors::InvalidArgument("Stack[", stack_name_, "] overflowed ", |
| 62 | "its max_size (", max_size_, ")"); |
| 63 | } |
| 64 | stack_.push_back(value); |
| 65 | return Status::OK(); |
| 66 | } |
| 67 | |
| 68 | Status Pop(TensorAndAllocation* value) { |
| 69 | mutex_lock l(mu_); |
| 70 | TF_RETURN_IF_ERROR(CheckNotClosed()); |
| 71 | if (stack_.empty()) { |
| 72 | return errors::InvalidArgument("Stack[", stack_name_, |
| 73 | "] is empty when calling Pop()."); |
| 74 | } |
| 75 | *value = stack_.back(); |
| 76 | stack_.pop_back(); |
| 77 | return Status::OK(); |
| 78 | } |
| 79 | |
| 80 | // We don't swap the first tensor on the stack and any subsequent tensors |
| 81 | // that share the buffer with the first tensor. |
| 82 | bool IsUsefulToSwap(const Tensor& tensor) const { |
| 83 | mutex_lock l(mu_); |
| 84 | if (stack_.empty()) { |
| 85 | return false; |
| 86 | } |
| 87 | const Tensor& first = stack_.front().tensor; |
| 88 | return !tensor.SharesBufferWith(first); |
| 89 | } |
| 90 | |
| 91 | void Close() { |
| 92 | mutex_lock l(mu_); |
| 93 | stack_.clear(); |
| 94 | closed_ = true; |
| 95 | } |
| 96 | |
| 97 | DataType ElemType() { return elem_type_; } |
| 98 |
no outgoing calls