1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef PREFETCHER_SESSION_H_
16 #define PREFETCHER_SESSION_H_
17 
18 #include <android-base/chrono_utils.h>
19 #include <android-base/unique_fd.h>
20 
21 #include <optional>
22 #include <memory>
23 #include <string>
24 #include <string_view>
25 #include <unordered_map>
26 #include <vector>
27 
28 namespace iorap {
29 namespace prefetcher {
30 
31 #ifndef READ_AHEAD_KIND
32 #define READ_AHEAD_KIND 1
33 enum class ReadAheadKind : uint32_t {
34   kFadvise = 0,
35   kMmapLocked = 1,
36   kMlock = 2,
37 };
38 #endif
39 
40 class Session {
41  public:
42   virtual bool RegisterFilePath(size_t path_id, std::string_view file_path) = 0;
43   virtual bool UnregisterFilePath(size_t path_id) = 0;
44 
45   // Immediately perform a readahead now.
46   // Fadvise: the readahead will have been queued by the kernel.
47   // MmapLocked/Mlock: the memory is pinned by the requested process.
48   virtual bool ReadAhead(size_t path_id, ReadAheadKind kind, size_t length, size_t offset) = 0;
49 
50   // Cancels a readahead previously done.
51   // The length/offset should match the call of ReadAhead.
52   virtual bool UnreadAhead(size_t path_id, ReadAheadKind kind, size_t length, size_t offset) = 0;
53 
54   // Multi-line detailed dump, e.g. for dumpsys.
55   // Single-line summary dump, e.g. for logcat.
56   virtual void Dump(std::ostream& os, bool multiline) const = 0;
57 
58   // Process the FD for kCreateFdSession.
59   // Assumes there's a compiled_trace.pb at the fd, calling this function
60   // will immediately process it and execute any read-aheads.
61   //
62   // FD is borrowed only for the duration of the function call.
63   virtual bool ProcessFd(int fd) = 0;
64 
65   // Get the session ID associated with this session.
66   // Session IDs are distinct, they are not used for new sessions.
67   virtual size_t SessionId() const = 0;
68 
69   // Get this session's description.
70   // Only useful for logging/dumping.
71   virtual const std::string& SessionDescription() const = 0;
72 
73   // Implicitly unregister any remaining file paths.
74   // All read-aheads are also cancelled.
~Session()75   virtual ~Session() {}
76 
77  protected:
78   Session();
79 };
80 
81 // Single-line summary dump of Session.
82 std::ostream& operator<<(std::ostream&os, const Session& session);
83 
84 class SessionBase : public Session {
85  public:
86   virtual void Dump(std::ostream& os, bool multiline) const override;
~SessionBase()87   virtual ~SessionBase() {}
88 
SessionId()89   virtual size_t SessionId() const override {
90     return session_id_;
91   }
92 
SessionDescription()93   virtual const std::string& SessionDescription() const override {
94     return description_;
95   }
96 
97   virtual bool ProcessFd(int fd) override;
98 
99  protected:
100   SessionBase(size_t session_id, std::string description);
101   std::optional<std::string_view> GetFilePath(size_t path_id) const;
102   bool RemoveFilePath(size_t path_id);
103   bool InsertFilePath(size_t path_id, std::string file_path);
104 
105   android::base::Timer timer_{};
106  private:
107   // Note: Store filename for easier debugging and for dumping.
108   std::unordered_map</*path_id*/size_t, std::string> path_map_;
109   size_t session_id_;
110   std::string description_;
111 };
112 
113 // In-process session.
114 class SessionDirect : public SessionBase {
115  public:
116   virtual bool RegisterFilePath(size_t path_id, std::string_view file_path) override;
117 
118   virtual bool UnregisterFilePath(size_t path_id) override;
119   virtual bool ReadAhead(size_t path_id,
120                          ReadAheadKind kind,
121                          size_t length,
122                          size_t offset);
123 
124   virtual bool UnreadAhead(size_t path_id,
125                            ReadAheadKind kind,
126                            size_t length,
127                            size_t offset) override;
128 
129   virtual bool ProcessFd(int fd) override;
130 
131   virtual void Dump(std::ostream& os, bool multiline) const override;
132 
133   virtual ~SessionDirect();
134 
SessionDirect(size_t session_id,std::string description)135   SessionDirect(size_t session_id, std::string description)
136     : SessionBase{session_id, std::move(description)} {
137   }
138  protected:
139   struct Entry {
140     size_t path_id;
141     ReadAheadKind kind;
142     size_t length;
143     size_t offset;
144 
145     constexpr bool operator==(const Entry& other) const {
146       return path_id == other.path_id &&
147         kind == other.kind &&
148         length == other.length &&
149         offset == other.offset;
150     }
151     constexpr bool operator!=(const Entry& other) const {
152       return !(*this == other);
153     }
154 
155     friend std::ostream& operator<<(std::ostream& os, const Entry& entry);
156   };
157 
158   struct EntryMapping {
159     Entry entry;
160     void* address;
161     bool success;
162   };
163 
164   // bool EntryReadAhead(const Entry& entry) const;
165   // bool EntryUnReadAhead(const Entry& entry) const;
166 
167   void UnmapWithoutErase(const EntryMapping& entry_mapping);
168   std::optional<android::base::unique_fd*> GetFdForPath(size_t path_id);
169 
170  private:
171   std::unordered_map</*path_id*/size_t, std::vector<EntryMapping>> entry_list_map_;
172   std::unordered_map</*path_id*/size_t, android::base::unique_fd> path_fd_map_;
173 
174  public:
175   friend std::ostream& operator<<(std::ostream& os, const SessionDirect::Entry& entry);
176 };
177 
178 std::ostream& operator<<(std::ostream& os, const SessionDirect::Entry& entry);
179 
180 class PrefetcherDaemon;
181 
182 // Out-of-process session. Requires prefetcher daemon.
183 class SessionIndirect : public SessionBase {
184  public:
185   virtual bool RegisterFilePath(size_t path_id, std::string_view file_path) override;
186 
187   virtual bool UnregisterFilePath(size_t path_id) override;
188   virtual bool ReadAhead(size_t path_id,
189                          ReadAheadKind kind,
190                          size_t length,
191                          size_t offset) override;
192 
193   virtual bool UnreadAhead(size_t path_id,
194                            ReadAheadKind kind,
195                            size_t length,
196                            size_t offset) override;
197 
198   virtual void Dump(std::ostream& os, bool multiline) const override;
199 
200   // Creates a new session indirectly.
201   // Writes to daemon the new session command.
202   SessionIndirect(size_t session_id,
203                   std::string description,
204                   std::shared_ptr<PrefetcherDaemon> daemon,
205                   bool send_command = true);
206 
207   // Destroys the current session.
208   // Writes to daemon that the session is to be destroyed.
209   virtual ~SessionIndirect();
210 
211  protected:
212   std::shared_ptr<PrefetcherDaemon> daemon_;
213 };
214 
215 // Out-of-process session. Requires prefetcher daemon.
216 class SessionIndirectSocket : public SessionIndirect {
217  public:
218   // Creates a new session indirectly.
219   // Writes to daemon the new session command.
220   SessionIndirectSocket(size_t session_id,
221                         int fd,
222                         std::string description,
223                         std::shared_ptr<PrefetcherDaemon> daemon);
224   // Destroys the current session.
225   // Writes to daemon that the session is to be destroyed.
226   virtual ~SessionIndirectSocket();
227 
228  private:
229 };
230 
231 
232 }  // namespace prefetcher
233 }  // namespace iorap
234 
235 #endif
236 
237