1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "immune_spaces.h"
18
19 #include <vector>
20 #include <tuple>
21
22 #include "gc/space/space-inl.h"
23 #include "mirror/object.h"
24 #include "oat_file.h"
25
26 namespace art {
27 namespace gc {
28 namespace collector {
29
Reset()30 void ImmuneSpaces::Reset() {
31 spaces_.clear();
32 largest_immune_region_.Reset();
33 }
34
CreateLargestImmuneRegion()35 void ImmuneSpaces::CreateLargestImmuneRegion() {
36 uintptr_t best_begin = 0u;
37 uintptr_t best_end = 0u;
38 uintptr_t best_heap_size = 0u;
39 uintptr_t cur_begin = 0u;
40 uintptr_t cur_end = 0u;
41 uintptr_t cur_heap_size = 0u;
42 using Interval = std::tuple</*start*/uintptr_t, /*end*/uintptr_t, /*is_heap*/bool>;
43 std::vector<Interval> intervals;
44 for (space::ContinuousSpace* space : GetSpaces()) {
45 uintptr_t space_begin = reinterpret_cast<uintptr_t>(space->Begin());
46 uintptr_t space_end = reinterpret_cast<uintptr_t>(space->Limit());
47 if (space->IsImageSpace()) {
48 // For the boot image, the boot oat file is always directly after. For app images it may not
49 // be if the app image was mapped at a random address.
50 space::ImageSpace* image_space = space->AsImageSpace();
51 // Update the end to include the other non-heap sections.
52 space_end = RoundUp(reinterpret_cast<uintptr_t>(image_space->GetImageEnd()), kPageSize);
53 // For the app image case, GetOatFileBegin is where the oat file was mapped during image
54 // creation, the actual oat file could be somewhere else.
55 const OatFile* const image_oat_file = image_space->GetOatFile();
56 if (image_oat_file != nullptr) {
57 intervals.push_back(Interval(reinterpret_cast<uintptr_t>(image_oat_file->Begin()),
58 reinterpret_cast<uintptr_t>(image_oat_file->End()),
59 /*image*/false));
60 }
61 }
62 intervals.push_back(Interval(space_begin, space_end, /*is_heap*/true));
63 }
64 std::sort(intervals.begin(), intervals.end());
65 // Intervals are already sorted by begin, if a new interval begins at the end of the current
66 // region then we append, otherwise we restart the current interval. To prevent starting an
67 // interval on an oat file, ignore oat files that are not extending an existing interval.
68 // If the total number of image bytes in the current interval is larger than the current best
69 // one, then we set the best one to be the current one.
70 for (const Interval& interval : intervals) {
71 const uintptr_t begin = std::get<0>(interval);
72 const uintptr_t end = std::get<1>(interval);
73 const bool is_heap = std::get<2>(interval);
74 VLOG(collector) << "Interval " << reinterpret_cast<const void*>(begin) << "-"
75 << reinterpret_cast<const void*>(end) << " is_heap=" << is_heap;
76 DCHECK_GE(end, begin);
77 DCHECK_GE(begin, cur_end);
78 // New interval is not at the end of the current one, start a new interval if we are a heap
79 // interval. Otherwise continue since we never start a new region with non image intervals.
80 if (begin != cur_end) {
81 if (!is_heap) {
82 continue;
83 }
84 // Not extending, reset the region.
85 cur_begin = begin;
86 cur_heap_size = 0;
87 }
88 cur_end = end;
89 if (is_heap) {
90 // Only update if the total number of image bytes is greater than the current best one.
91 // We don't want to count the oat file bytes since these contain no java objects.
92 cur_heap_size += end - begin;
93 if (cur_heap_size > best_heap_size) {
94 best_begin = cur_begin;
95 best_end = cur_end;
96 best_heap_size = cur_heap_size;
97 }
98 }
99 }
100 largest_immune_region_.SetBegin(reinterpret_cast<mirror::Object*>(best_begin));
101 largest_immune_region_.SetEnd(reinterpret_cast<mirror::Object*>(best_end));
102 VLOG(collector) << "Immune region " << largest_immune_region_.Begin() << "-"
103 << largest_immune_region_.End();
104 }
105
AddSpace(space::ContinuousSpace * space)106 void ImmuneSpaces::AddSpace(space::ContinuousSpace* space) {
107 DCHECK(spaces_.find(space) == spaces_.end()) << *space;
108 // Bind live to mark bitmap if necessary.
109 if (space->GetLiveBitmap() != space->GetMarkBitmap()) {
110 CHECK(space->IsContinuousMemMapAllocSpace());
111 space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap();
112 }
113 spaces_.insert(space);
114 CreateLargestImmuneRegion();
115 }
116
operator ()(space::ContinuousSpace * a,space::ContinuousSpace * b) const117 bool ImmuneSpaces::CompareByBegin::operator()(space::ContinuousSpace* a, space::ContinuousSpace* b)
118 const {
119 return a->Begin() < b->Begin();
120 }
121
ContainsSpace(space::ContinuousSpace * space) const122 bool ImmuneSpaces::ContainsSpace(space::ContinuousSpace* space) const {
123 return spaces_.find(space) != spaces_.end();
124 }
125
126 } // namespace collector
127 } // namespace gc
128 } // namespace art
129